Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions rust/lit-core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 26 additions & 3 deletions rust/lit-core/lit-api-core/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::collections::HashMap;
use std::fmt;
use std::future::Future;

use lit_observability::PRIVACY_MODE_TAG;
use lit_observability::logging::set_request_context;
use lit_observability::metrics::counter;
use opentelemetry::propagation::Injector;
use rocket::Request;
use rocket::request::{FromRequest, Outcome};
Expand All @@ -13,11 +15,12 @@ use tokio::task::futures::TaskLocalFuture;
use tokio::task_local;

use crate::error::{EC, Error, Result, conversion_err_code, validation_err_code};
use crate::observability::http::HttpMetrics;

pub const HEADER_KEY_X_CORRELATION_ID: &str = "X-Correlation-Id";
pub const HEADER_KEY_X_REQUEST_ID: &str = "X-Request-Id";
pub const HEADER_KEY_X_LIT_SDK_VERSION: &str = "X-Lit-SDK-Version";

pub const HEADER_KEY_X_PRIVACY_MODE: &str = "X-Privacy-Mode";
pub const TRACKING_LOG_KEY_LIT_SDK_VERSION: &str = "lit_sdk_version";

task_local! {
Expand Down Expand Up @@ -199,17 +202,37 @@ where
/// Returns (request_id, correlation_id) tuple.
/// - request_id: X-Request-Id header, falls back to X-Correlation-Id
/// - correlation_id: X-Correlation-Id header, falls back to X-Request-Id
/// - privacy_mode: X-Privacy-Mode header, if present, will be added to the request_id and correlation_id
pub(crate) fn extract_request_and_correlation_ids(
req: &Request<'_>,
) -> (Option<String>, Option<String>) {
let x_request_id = req.headers().get(HEADER_KEY_X_REQUEST_ID).next().map(|v| v.to_string());
let x_correlation_id =
req.headers().get(HEADER_KEY_X_CORRELATION_ID).next().map(|v| v.to_string());

// privacy_mode: X-Privacy-Mode header, if present, will be added to the request_id and correlation_id
let x_privacy_mode = req.headers().get(HEADER_KEY_X_PRIVACY_MODE).next().map(|v| v.to_string());

// request_id: prefer X-Request-Id, fall back to X-Correlation-Id
let request_id = x_request_id.clone().or_else(|| x_correlation_id.clone());
let mut request_id = x_request_id.clone().or_else(|| x_correlation_id.clone());
// correlation_id: prefer X-Correlation-Id, fall back to X-Request-Id
let correlation_id = x_correlation_id.or(x_request_id);
let mut correlation_id = x_correlation_id.or(x_request_id);

if x_privacy_mode.is_some() {
counter::add_one(HttpMetrics::PrivacyModeRequest, &[]);

let privacy_suffix = format!("_{}", PRIVACY_MODE_TAG);
if let Some(ref id) = request_id {
if !id.ends_with(&privacy_suffix) {
request_id = Some(format!("{}_{}", id, PRIVACY_MODE_TAG));
}
}
if let Some(ref id) = correlation_id {
if !id.ends_with(&privacy_suffix) {
correlation_id = Some(format!("{}_{}", id, PRIVACY_MODE_TAG));
}
}
}

(request_id, correlation_id)
}
Expand Down
2 changes: 2 additions & 0 deletions rust/lit-core/lit-api-core/src/observability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub mod http {

pub enum HttpMetrics {
ServiceRequest,
PrivacyModeRequest,
ServiceResponse,
}

Expand All @@ -91,6 +92,7 @@ pub mod http {
fn get_name(&self) -> &str {
match self {
Self::ServiceRequest => "request",
Self::PrivacyModeRequest => "request.privacy_mode",
Self::ServiceResponse => "response",
}
}
Expand Down
3 changes: 3 additions & 0 deletions rust/lit-core/lit-observability/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use tracing_subscriber::EnvFilter;
use tracing_subscriber::{fmt, prelude::*};

use lit_core::error::Result;
pub const PRIVACY_MODE_TAG: &str = "lit_privacy_mode";

#[cfg(feature = "channels")]
pub mod channels;
Expand Down Expand Up @@ -108,5 +109,7 @@ pub async fn create_providers(
.with(MetricsLayer::new(meter_provider.clone()))
.with(OpenTelemetryLayer::new(tracer));

let sub = sub.with(logging::privacy_filter::PrivacyModeLayer);

Ok((tracing_provider, meter_provider, sub, logger_provider))
}
6 changes: 4 additions & 2 deletions rust/lit-core/lit-observability/src/logging/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::str::FromStr;

use crate::config::LitObservabilityConfig;
use crate::{config::LitObservabilityConfig, logging::privacy_filter::PrivacyModeLayer};
use lit_core::{config::LitConfig, error::Result};
use opentelemetry_otlp::TonicExporterBuilder;
use opentelemetry_sdk::{Resource, runtime};
Expand All @@ -11,7 +11,7 @@ use crate::error::unexpected_err;

mod context_layer;
mod event_format;

pub mod privacy_filter;
// Re-export context layer components for use by lit-node
pub use context_layer::{
ContextAwareOtelLogLayer, RequestContext, clear_task_request_context, get_request_context,
Expand All @@ -37,6 +37,7 @@ pub fn simple_logging_subscriber(

Ok(tracing_subscriber::registry()
.with(level_filter)
.with(PrivacyModeLayer)
.with(fmt::layer().event_format(custom_formatter)))
}

Expand Down Expand Up @@ -65,6 +66,7 @@ pub fn simple_file_logging_subscriber(

return Ok(tracing_subscriber::registry()
.with(level_filter)
.with(PrivacyModeLayer)
.with(fmt::layer().event_format(custom_formatter.clone()))
.with(fmt::layer().event_format(custom_formatter).with_writer(file_appender)));
}
Expand Down
36 changes: 36 additions & 0 deletions rust/lit-core/lit-observability/src/logging/privacy_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::PRIVACY_MODE_TAG;
use crate::logging::get_request_context;

pub struct PrivacyModeLayer;

impl<S> tracing_subscriber::Layer<S> for PrivacyModeLayer
where
S: tracing::Subscriber,
{
fn enabled(
&self, _metadata: &tracing::Metadata<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>,
) -> bool {
let ctx = get_request_context();
if let Some(ctx) = ctx {
if let Some(request_id) = ctx.request_id {
if request_id.contains(PRIVACY_MODE_TAG) {
return false;
}
}
}
true
}

fn on_event(
&self, _event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>,
) {
// Events are filtered by enabled() above
}

fn on_new_span(
&self, _attrs: &tracing::span::Attributes<'_>, _id: &tracing::span::Id,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) {
// Spans are filtered by enabled() above
}
}
20 changes: 10 additions & 10 deletions rust/lit-node/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions rust/lit-node/lit-node/tests/common/lit_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use anyhow::Result;
use ethers::core::k256::ecdsa::SigningKey;
use ethers::signers::Wallet;
use ethers::types::U256;
use lit_api_core::context::HEADER_KEY_X_PRIVACY_MODE;
use lit_node_testnet::end_user::EndUser;
use lit_node_testnet::node_collection::{NodeIdentityKey, get_identity_pubkeys_from_node_set};
use lit_node_testnet::testnet::Testnet;
Expand Down Expand Up @@ -226,6 +227,7 @@ pub async fn generate_session_sigs_and_execute_lit_action(
&session_sigs_and_node_set,
epoch,
key_set_id,
false,
)
.await;
debug!("execute_resps: {:?}", execute_resp);
Expand All @@ -240,6 +242,7 @@ pub async fn execute_lit_action_session_sigs(
session_sigs_and_node_set: &[SessionSigAndNodeSet],
epoch: u64,
key_set_id: String,
add_privacy_mode: bool,
) -> Result<Vec<GenericResponse<JsonExecutionResponse>>> {
info!(
"executing lit action with session sigs. Lit Action keyset id: {:?}",
Expand All @@ -251,10 +254,15 @@ pub async fn execute_lit_action_session_sigs(
.map(|sig_and_nodeset| sig_and_nodeset.node.clone())
.collect::<Vec<_>>();
let my_private_key = OsRng.r#gen();
let response = lit_sdk::ExecuteFunctionRequest::new()
.url_prefix(lit_sdk::UrlPrefix::from_socket_address(
&nodesets.first().unwrap().socket_address,
))
let response = lit_sdk::ExecuteFunctionRequest::new().url_prefix(
lit_sdk::UrlPrefix::from_socket_address(&nodesets.first().unwrap().socket_address),
);
let response = match add_privacy_mode {
true => response.add_custom_header(HEADER_KEY_X_PRIVACY_MODE, "true"),
false => response,
};

let response = response
.node_set(
session_sigs_and_node_set
.iter()
Expand Down
1 change: 1 addition & 0 deletions rust/lit-node/lit-node/tests/common/web_user_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ pub async fn generate_session_sigs_execute_lit_action(
&session_sigs_and_node_set,
2,
key_set_id,
false,
)
.await
}
16 changes: 14 additions & 2 deletions rust/lit-node/lit-node/tests/integration/lit_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,15 +682,26 @@ pub mod litactions {
}

#[doc = "Signing with MGB PKP within its permitted Lit Action"]
#[test_case(true, "Anyone can sign with a MGB PKP within its permitted Lit Action")]
#[test_case(
true,
"Anyone can sign with a MGB PKP within its permitted Lit Action",
false
)]
#[test_case(
false,
"Any other PKP can sign with a different MGB PKP within its permitted Lit Action"
"Any other PKP can sign with a different MGB PKP within its permitted Lit Action",
false
)]
#[test_case(
true,
"Anyone can sign with a MGB PKP within its permitted Lit Action - Privacy Mode Enabled",
true
Comment on lines +695 to +698
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The privacy mode test case doesn't programmatically verify that logs are suppressed when privacy mode is enabled. According to the PR description, this test is meant to be verified manually by inspecting logs. Consider adding a comment explaining that this test case should be validated by observing that request ID logs are suppressed when privacy mode is enabled, to help future maintainers understand the test's purpose.

Copilot uses AI. Check for mistakes.
)]
#[tokio::test]
pub async fn session_sig_with_mgb_pkp_lit_action(
use_eoa_session_sig: bool,
test_description: &str,
add_privacy_mode: bool,
) {
setup_logging();
info!(test_description);
Expand Down Expand Up @@ -814,6 +825,7 @@ pub mod litactions {
&session_sigs_and_node_set,
2,
key_set_id,
add_privacy_mode,
)
.await
.expect("Could not execute lit action");
Expand Down
Loading