From 48071b7ae722ac915c678fe518110aee988e6d74 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Sat, 21 Feb 2026 01:22:13 +1100 Subject: [PATCH] Add --jwt-secret-path to lcli mock-el (#8864) Co-Authored-By: Jimmy Chen --- lcli/src/main.rs | 12 +++++++++++- lcli/src/mock_el.rs | 24 ++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lcli/src/main.rs b/lcli/src/main.rs index a21dfd4386..63dd0f2c5b 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -492,10 +492,20 @@ fn main() { .long("jwt-output-path") .value_name("PATH") .action(ArgAction::Set) - .required(true) + .required_unless_present("jwt-secret-path") + .conflicts_with("jwt-secret-path") .help("Path to write the JWT secret.") .display_order(0) ) + .arg( + Arg::new("jwt-secret-path") + .long("jwt-secret-path") + .value_name("PATH") + .action(ArgAction::Set) + .help("Path to an existing hex-encoded JWT secret file. \ + When provided, this secret is used instead of the default.") + .display_order(0) + ) .arg( Arg::new("listen-address") .long("listen-address") diff --git a/lcli/src/mock_el.rs b/lcli/src/mock_el.rs index d6bdfb0d71..544010b6a2 100644 --- a/lcli/src/mock_el.rs +++ b/lcli/src/mock_el.rs @@ -2,7 +2,7 @@ use clap::ArgMatches; use clap_utils::{parse_optional, parse_required}; use environment::Environment; use execution_layer::{ - auth::JwtKey, + auth::{JwtKey, strip_prefix}, test_utils::{ Config, DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, MockExecutionConfig, MockServer, }, @@ -13,7 +13,8 @@ use std::sync::Arc; use types::*; pub fn run(mut env: Environment, matches: &ArgMatches) -> Result<(), String> { - let jwt_path: PathBuf = parse_required(matches, "jwt-output-path")?; + let jwt_output_path: Option = parse_optional(matches, "jwt-output-path")?; + let jwt_secret_path: Option = parse_optional(matches, "jwt-secret-path")?; let listen_addr: Ipv4Addr = parse_required(matches, "listen-address")?; let listen_port: u16 = parse_required(matches, "listen-port")?; let all_payloads_valid: bool = parse_required(matches, "all-payloads-valid")?; @@ -25,8 +26,23 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< let handle = env.core_context().executor.handle().unwrap(); let spec = Arc::new(E::default_spec()); - let jwt_key = JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap(); - std::fs::write(jwt_path, hex::encode(DEFAULT_JWT_SECRET)).unwrap(); + + let jwt_key = if let Some(secret_path) = jwt_secret_path { + let hex_str = std::fs::read_to_string(&secret_path) + .map_err(|e| format!("Failed to read JWT secret file: {}", e))?; + let secret_bytes = hex::decode(strip_prefix(hex_str.trim())) + .map_err(|e| format!("Invalid hex in JWT secret file: {}", e))?; + JwtKey::from_slice(&secret_bytes) + .map_err(|e| format!("Invalid JWT secret length (expected 32 bytes): {}", e))? + } else if let Some(jwt_path) = jwt_output_path { + let jwt_key = JwtKey::from_slice(&DEFAULT_JWT_SECRET) + .map_err(|e| format!("Default JWT secret invalid: {}", e))?; + std::fs::write(jwt_path, hex::encode(jwt_key.as_bytes())) + .map_err(|e| format!("Failed to write JWT secret to output path: {}", e))?; + jwt_key + } else { + return Err("either --jwt-secret-path or --jwt-output-path must be provided".to_string()); + }; let config = MockExecutionConfig { server_config: Config {