Skip to content

Conversation

@addisonbeck
Copy link
Contributor

@addisonbeck addisonbeck commented Dec 20, 2025

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-27800

📔 Objective

🚨 Breaking Changes

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation
    team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed
    issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

- Create log_callback.rs module with UNIFFI callback trait definition
- Add Send + Sync bounds for thread-safe callback invocation
- Re-export LogCallback from lib.rs for UNIFFI binding generation
- Include test validating trait implementation with Arc

Part of PM-27800: Expose SDK Tracing to Flight Recorder
…g integration

- Add CallbackLayer struct implementing tracing_subscriber::Layer
- Implement MessageVisitor with record_debug for message extraction
- Add target filtering to prevent infinite callback recursion
- Include error logging to platform loggers for mobile debugging
- Add basic compilation tests for layer and visitor
- Remove weak test_message_visitor_extracts_message test

CallbackLayer bridges SDK tracing to UNIFFI callback interface.
MessageVisitor extracts formatted messages from trace events using
only record_debug (sufficient per trait default implementations).

Target filtering prevents recursion when logging callback errors.
…nal logging

Refactor init_logger to accept optional callback parameter and compose
CallbackLayer with existing tracing infrastructure from PM-26930.

Changes:
- Add callback parameter: fn init_logger(Option<Arc<dyn LogCallback>>)
- Extract base registry construction to avoid platform duplication
- Use Option layer pattern for type-safe conditional layer addition
- Temporarily pass None at call site (updated in next TODO)

Layer composition order:
1. Base registry (fmtlayer + filter)
2. CallbackLayer (optional - when callback provided)
3. Platform layers (oslog/android_logger/none)

Each layer observes events independently. When callback is None,
Option<CallbackLayer> becomes a no-op layer with no overhead.
…e logging

- Add optional log_callback parameter to Client::new() constructor
- Pass callback to init_logger() for integration with CallbackLayer
- Update LogCallback trait to use uniffi::export(with_foreign) pattern
- Add comprehensive test suite with mock implementations
- Verify backward compatibility with None callback
- All tests pass: callback receives logs and SDK works without callback

This enables mobile clients to register callbacks for forwarding SDK
logs to Flight Recorder observability systems following PM-27800 spec.
- Add CallbackError variant to BitwardenError enum
- Implement From<UnexpectedUniFFICallbackError> conversion
- Add test validating SDK stability when callbacks fail

Enables proper error handling when mobile callbacks throw exceptions.
Mobile exceptions are converted to BitwardenError::CallbackError at
the FFI boundary, logged to platform loggers, and SDK continues
normal operation without crashes.

Test coverage:
- test_callback_error_does_not_crash_sdk validates resilience

Resolves PM-27800 error handling requirements.
…ency

Remove test_client_with_callback_receives_logs which fails due to
Once::call_once() in init_logger. The logger initializes once per
process, causing test interference when multiple tests register
different callbacks.

The remaining tests provide sufficient coverage:
- test_callback_error_does_not_crash_sdk validates error handling
- test_client_without_callback_still_works validates backward compat
- Callback invocation is implicitly validated by log output

Future callback integration tests should use integration test
directory (tests/) where each test runs in a separate process.
…alidation

Replace test_client_without_callback_still_works with
test_callback_receives_logs to validate core callback functionality.

Rationale:
- Backward compatibility (None callback) tests trivial Option handling
- Happy path (successful callback) tests core feature implementation
- Validates callback receives correct level, target, and message data
- Removes test_callback_error_does_not_crash_sdk to avoid Once constraint

Error handling remains validated through CallbackError implementation
and From<UnexpectedUniFFICallbackError> conversion. Integration tests
will provide comprehensive error and edge case coverage.

Test passes consistently, proves primary use case works.
…callback

- Created 5 integration tests in tests/ directory for callback validation
- Each test runs as separate process, avoiding Once initialization constraint
- TC-001: Happy path validation (callback receives logs with correct data)
- TC-002: Multiple log levels (INFO, WARN, ERROR) forwarded correctly
- TC-004: Thread safety validation (concurrent callback invocations)
- TC-005: Error handling (callback failures don't crash SDK)
- TC-007: MessageVisitor validates message field extraction

Made error module public to enable integration tests to access BitwardenError
type for test implementations. All tests pass and validate core callback
functionality comprehensively.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 20, 2025

Logo
Checkmarx One – Scan Summary & Detailsbb598d0c-0641-46eb-a17c-c5179a837ef3

Great job! No new security vulnerabilities introduced in this pull request

@github-actions
Copy link
Contributor

github-actions bot commented Dec 20, 2025

🔍 SDK Breaking Change Detection Results

SDK Version: PM-27800-expose-sdk-tracing-flight-recorder (7fbcfda)
Completed: 2025-12-22 18:09:45 UTC
Total Time: 216s

Client Status Details
typescript ✅ No breaking changes detected TypeScript compilation passed with new SDK version - View Details

Breaking change detection completed. View SDK workflow

- Add crate-level documentation to all integration test files
- Run cargo fmt to fix blank line spacing issues
- Resolves CI Check Style and missing-docs lint failures
Rustfmt requires a blank line between crate-level documentation and
the first use statement. This fixes the remaining Check Style failures.
Nightly rustfmt enforces stricter import grouping:
- std imports first
- blank line separator
- external crate imports next
- consolidate multiple std imports with braces

This resolves all remaining Check Style lint failures.
Nightly rustfmt requires alphabetical ordering within grouped imports,
with capital letters before lowercase (Layer before layer::Context).
The error module was already public before these changes and already
had missing documentation warnings suppressed in other contexts.
Adding #[allow(missing_docs)] to match the pattern used for other
public modules (auth, crypto, platform, tool, vault) in this crate.
The error module doesn't need to be public for the LogCallback trait
to work. The trait uses crate::Result<()> which is accessible within
the crate even with a private module. Making it public unnecessarily
exposed all error variants to the public API.

This reverts the pub mod error change and removes the need for
#[allow(missing_docs)].
Integration tests need access to BitwardenError to construct error
variants. Rather than making the entire error module public (which
exposes 40+ undocumented types), re-export just BitwardenError at
the crate root.

This allows tests to use bitwarden_uniffi::BitwardenError while
keeping the error module private.
Nightly rustfmt requires pub use statements (and their comments) to
come before private use statements.
The re-export approach still required documentation for all error
variants. Making the error module public with #[allow(missing_docs)]
is simpler and matches the pattern used for other public modules
(auth, crypto, platform, tool, vault).

This reverts integration tests back to using the error:: path.
SDK has -D clippy::unwrap-used which forbids unwrap() even in tests.
Replace all unwrap() calls with expect() to provide better error
messages if tests fail.
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.

2 participants