jlcodes99/cockpit-tools · info
email regex should be valid
Error message
email regex should be valid
What it means
The logger builds a static LazyLock<Regex> used to redact email addresses from log output, calling .expect("email regex should be valid"). Since the pattern is a compile-time constant that is known-valid, this panic can only fire if the regex source in the code is edited into an invalid form — a developer/build-time defect, not a runtime input problem.
Source
Thrown at crates/cockpit-core/src/modules/logger.rs:20
use chrono::{DateTime, Duration, Local};
use regex::{Captures, Regex};
use std::fs;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use tracing::{error, info, warn};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
const LOG_FILE_PREFIX: &str = "app.log";
const LOG_RETENTION_DAYS: i64 = 3;
const DEFAULT_LOG_TAIL_LINES: usize = 200;
const MIN_LOG_TAIL_LINES: usize = 20;
const MAX_LOG_TAIL_LINES: usize = 5000;
const LOG_TAIL_SCAN_CHUNK_BYTES: usize = 8192;
static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(?i)\b[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}\b")
.expect("email regex should be valid")
});
struct LocalTimer;
impl tracing_subscriber::fmt::time::FormatTime for LocalTimer {
fn format_time(&self, w: &mut tracing_subscriber::fmt::format::Writer<'_>) -> std::fmt::Result {
let now = chrono::Local::now();
write!(w, "{}", now.to_rfc3339())
}
}
pub fn get_log_dir() -> Result<PathBuf, String> {
let data_dir = get_data_dir()?;
let log_dir = data_dir.join("logs");
if !log_dir.exists() {
fs::create_dir_all(&log_dir).map_err(|e| format!("创建日志目录失败: {}", e))?;
}View on GitHub (pinned to 1ed8b77992)
Solutions
- Validate the pattern with regex::Regex::new in a unit test or quick check before building.
- Fix the regex syntax; remove PCRE-only constructs (lookarounds, backreferences) unsupported by the regex crate.
- If pattern validity must be dynamic, replace .expect with graceful error handling returning a no-redaction fallback.
- Pin/align the regex crate version if a feature used by the pattern disappeared.
Example fix
// before
Regex::new(r"(?i)\b[a-z0-9._%+\-]+(?=@)[a-z0-9.@]+\b")
.expect("email regex should be valid") // lookahead: unsupported -> panic
// after
Regex::new(r"(?i)\b[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}\b")
.expect("email regex should be valid") Defensive patterns
Strategy: validation
Validate before calling
#[cfg(test)]
#[test]
fn email_regex_is_valid() {
Regex::new(r"(?i)\b[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}\b")
.expect("email regex should be valid");
} Try / catch
static EMAIL_REGEX: LazyLock<Option<Regex>> = LazyLock::new(|| {
Regex::new(r"(?i)\b[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}\b").ok()
}); // redact only when Some Prevention
- Add a unit test asserting the redaction regex compiles
- Avoid PCRE-only constructs (lookarounds, backreferences) — the regex crate rejects them
- Lint regex literals in code review when touching logger redaction rules
- Pin the regex crate version so pattern features stay supported
When it happens
Trigger: Logger initialization when the hardcoded regex literal is invalid — i.e. only after someone edits the EMAIL_REGEX pattern with a syntax error, bad escape, or an unsupported feature for the installed regex crate version.
Common situations: Hand-editing the redaction pattern (e.g. adding a lookahead, which the regex crate does not support); upgrading/downgrading the regex crate across feature changes; copy-pasting a PCRE-style pattern into the Rust regex crate.
Related errors
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/dafeba068c247879.
Report an issue: GitHub.