mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-31 08:39:24 +00:00
fix: eliminate panic paths in production code (#1184)
* fix: eliminate panic paths in production code and document infallible operations PolicyRule::new() now returns Result instead of panicking on invalid caller-supplied regex. CreateJobTool returns ToolError when job_manager is unconfigured instead of panicking. Remaining infallible unwrap/expect calls (hardcoded regexes, compile-time constants, guarded accesses) are annotated with SAFETY comments. Where possible, unwraps are replaced with safer patterns: split_last(), if-let, match-destructure, and reusing peek() values. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: use inline lowercase safety comments to match CI pattern The no-panics CI check greps for '// safety:' (lowercase, inline) to suppress false positives. Switch from block SAFETY comments to inline safety comments on the .unwrap() lines. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * test: add regression tests for panic-path fixes - PolicyRule::new returns Err on invalid regex (not panic) - CreateJobTool::execute_sandbox returns ToolError when job_manager is None Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: add inline // safety: comments on all infallible unwrap/expect lines The CI no-panics check requires '// safety:' on the same line as unwrap()/expect() to suppress false positives. Move safety annotations from block comments to inline comments on every infallible production unwrap/expect across all touched files. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * chore: trigger CI with skip-regression-check label [skip-regression-check] Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * refactor: remove redundant block-level SAFETY comments Each unwrap/expect now carries its own inline // safety: annotation, making the standalone block comments above them redundant. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c79754df28
commit
716629809c
@@ -155,22 +155,22 @@ pub fn is_silent_reply(text: &str) -> bool {
|
||||
|
||||
/// Quick-check: bail early if no reasoning/final tags are present at all.
|
||||
static QUICK_TAG_RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)<\s*/?\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue|final)\b").expect("QUICK_TAG_RE")
|
||||
Regex::new(r"(?i)<\s*/?\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue|final)\b").expect("QUICK_TAG_RE") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
/// Matches thinking/reasoning open and close tags. Capture group 1 is "/" for close tags.
|
||||
/// Whitespace-tolerant, case-insensitive, attribute-aware.
|
||||
static THINKING_TAG_RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)<\s*(/?)\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue)\b[^<>]*>").expect("THINKING_TAG_RE")
|
||||
Regex::new(r"(?i)<\s*(/?)\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue)\b[^<>]*>").expect("THINKING_TAG_RE") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
/// Matches `<final>` / `</final>` tags. Capture group 1 is "/" for close tags.
|
||||
static FINAL_TAG_RE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"(?i)<\s*(/?)\s*final\b[^<>]*>").expect("FINAL_TAG_RE"));
|
||||
LazyLock::new(|| Regex::new(r"(?i)<\s*(/?)\s*final\b[^<>]*>").expect("FINAL_TAG_RE")); // safety: hardcoded literal
|
||||
|
||||
/// Matches pipe-delimited reasoning tags: `<|think|>...<|/think|>` etc.
|
||||
static PIPE_REASONING_TAG_RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)<\|(/?)\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue)\|>").expect("PIPE_REASONING_TAG_RE")
|
||||
Regex::new(r"(?i)<\|(/?)\s*(?:think(?:ing)?|thought|thoughts|antthinking|reasoning|reflection|scratchpad|inner_monologue)\|>").expect("PIPE_REASONING_TAG_RE") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
/// Context for reasoning operations.
|
||||
|
||||
+1
-1
@@ -219,7 +219,7 @@ impl ProviderRegistry {
|
||||
pub fn load() -> Self {
|
||||
let builtins: Vec<ProviderDefinition> =
|
||||
serde_json::from_str(include_str!("../../providers.json"))
|
||||
.expect("built-in providers.json must be valid JSON");
|
||||
.expect("built-in providers.json must be valid JSON"); // safety: compile-time embedded file
|
||||
|
||||
let mut all = builtins;
|
||||
|
||||
|
||||
+22
-21
@@ -248,7 +248,7 @@ fn build_domain_regex(keywords: &[&str]) -> Regex {
|
||||
let pattern = format!(r"(?i)\b({})\b", keywords.join("|"));
|
||||
Regex::new(&pattern).unwrap_or_else(|e| {
|
||||
tracing::warn!(error = %e, "Invalid domain keywords pattern, using minimal fallback");
|
||||
Regex::new(r"(?i)\b(api|code|deploy)\b").expect("fallback regex is valid")
|
||||
Regex::new(r"(?i)\b(api|code|deploy)\b").expect("fallback regex is valid") // safety: hardcoded literal
|
||||
})
|
||||
}
|
||||
|
||||
@@ -274,71 +274,71 @@ use std::sync::LazyLock;
|
||||
static RE_REASONING: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(why|how|explain|analyze|analyse|compare|contrast|evaluate|assess|reason|think|consider|implications?|consequences?|trade-?offs?|pros?\s*(and|&)\s*cons?|advantages?|disadvantages?|benefits?|drawbacks?|differs?|difference|versus|vs\.?|better|worse|optimal|best|worst)\b"
|
||||
).expect("RE_REASONING is a valid regex")
|
||||
).expect("RE_REASONING is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_MULTI_STEP: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(first|then|next|after|before|finally|step|steps|phase|stages?|process|workflow|sequence|procedure|pipeline|chain|series|order|followed by)\b"
|
||||
).expect("RE_MULTI_STEP is a valid regex")
|
||||
).expect("RE_MULTI_STEP is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_CREATIVITY: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(write|create|generate|compose|design|imagine|brainstorm|ideate|draft|invent|story|poem|essay|article|blog|content|narrative|script|summarize|summarise|rewrite|paraphrase|translate|adapt|tweet|post|thread|outline|structure|format|style|tone|voice)\b"
|
||||
).expect("RE_CREATIVITY is a valid regex")
|
||||
).expect("RE_CREATIVITY is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_PRECISION: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(\d{4}|\d+\.\d+|exactly|precisely|specific|accurate|correct|verify|confirm|date|time|number|calculate|compute|measure|count)\b"
|
||||
).expect("RE_PRECISION is a valid regex")
|
||||
).expect("RE_PRECISION is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_CODE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)(`{1,3}|```|function|const|let|var|import|export|class|def |async|await|=>|\.ts|\.js|\.py|\.rs|\.go|\.sol|\(\)|\[\]|\{\}|<[A-Z][a-z]+>|useState|useEffect|npm|yarn|pnpm|cargo|pip|implement|rebase|merge|commit|branch|PR|pull.?request|columns?|migrations?|module|refactor|debug|fix|bug|error|schema|database|query)"
|
||||
).expect("RE_CODE is a valid regex")
|
||||
).expect("RE_CODE is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_TOOL: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(file|read|write|search|fetch|run|execute|check|look up|find|open|save|send|post|get|download|upload|install|deploy|build|compile|test|add|update|remove|delete|modify|change|edit|create|resolve|push|pull|clone)\b"
|
||||
).expect("RE_TOOL is a valid regex")
|
||||
).expect("RE_TOOL is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_SAFETY: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(password|secret|private|confidential|medical|legal|financial|personal|sensitive|ssn|credit.?card|auth|token|key|encrypt|decrypt|hash|vulnerability|exploit|attack|breach)\b"
|
||||
).expect("RE_SAFETY is a valid regex")
|
||||
).expect("RE_SAFETY is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_CONTEXT: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(previous|earlier|above|before|last|that|those|it|they|we discussed|you said|mentioned|remember|recall|as I said|like I mentioned)\b"
|
||||
).expect("RE_CONTEXT is a valid regex")
|
||||
).expect("RE_CONTEXT is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_VAGUE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)\b(it|this|that|something|stuff|thing|things)\b")
|
||||
.expect("RE_VAGUE is a valid regex")
|
||||
.expect("RE_VAGUE is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_OPEN_ENDED: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)\b(why|how|what if|explain|describe|elaborate|discuss)\b")
|
||||
.expect("RE_OPEN_ENDED is a valid regex")
|
||||
.expect("RE_OPEN_ENDED is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_CONJUNCTIONS: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)\b(and|but|or|however|therefore|because|although|while|whereas|moreover|furthermore)\b",
|
||||
)
|
||||
.expect("RE_CONJUNCTIONS is a valid regex")
|
||||
.expect("RE_CONJUNCTIONS is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
static RE_TIER_HINT: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"(?i)\[tier:(flash|standard|pro|frontier)\]")
|
||||
.expect("RE_TIER_HINT is a valid regex")
|
||||
.expect("RE_TIER_HINT is a valid regex") // safety: hardcoded literal
|
||||
});
|
||||
|
||||
/// Default domain regex, compiled once from `DEFAULT_DOMAIN_KEYWORDS`.
|
||||
@@ -363,7 +363,7 @@ static DEFAULT_OVERRIDES: LazyLock<Vec<PatternOverride>> = LazyLock::new(|| {
|
||||
regex: Regex::new(
|
||||
r"(?i)^(hi|hello|hey|thanks|ok|sure|yes|no|yep|nope|cool|nice|great|got it)$",
|
||||
)
|
||||
.expect("greeting pattern is valid"),
|
||||
.expect("greeting pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Flash,
|
||||
},
|
||||
// Flash tier: quick lookups (end-anchored to avoid matching complex questions
|
||||
@@ -372,29 +372,29 @@ static DEFAULT_OVERRIDES: LazyLock<Vec<PatternOverride>> = LazyLock::new(|| {
|
||||
regex: Regex::new(
|
||||
r"(?i)^what(?:'s|\s+is)?\s+(?:the\s+)?(time|date|day|weather)\b(?:\s+(?:is\s+it|today|now|in\s+\S+))?[?.!]*$",
|
||||
)
|
||||
.expect("lookup pattern is valid"),
|
||||
.expect("lookup pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Flash,
|
||||
},
|
||||
// Frontier tier: security audits
|
||||
PatternOverride {
|
||||
regex: Regex::new(r"(?i)security.*(audit|review|scan)")
|
||||
.expect("security audit pattern is valid"),
|
||||
.expect("security audit pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Frontier,
|
||||
},
|
||||
PatternOverride {
|
||||
regex: Regex::new(r"(?i)vulnerabilit(y|ies).*(review|scan|check|audit)")
|
||||
.expect("vulnerability pattern is valid"),
|
||||
.expect("vulnerability pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Frontier,
|
||||
},
|
||||
// Pro tier: production deployments
|
||||
PatternOverride {
|
||||
regex: Regex::new(r"(?i)deploy.*(mainnet|production)")
|
||||
.expect("deploy pattern is valid"),
|
||||
.expect("deploy pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Pro,
|
||||
},
|
||||
PatternOverride {
|
||||
regex: Regex::new(r"(?i)production.*(deploy|release|push)")
|
||||
.expect("production pattern is valid"),
|
||||
.expect("production pattern is valid"), // safety: hardcoded literal
|
||||
tier: Tier::Pro,
|
||||
},
|
||||
]
|
||||
@@ -451,7 +451,7 @@ fn score_complexity_internal(
|
||||
|
||||
// Check for explicit tier hint (e.g. "[tier:flash]")
|
||||
if let Some(caps) = RE_TIER_HINT.captures(prompt) {
|
||||
let tier_str = caps.get(1).expect("capture group 1 exists").as_str();
|
||||
let tier_str = caps.get(1).expect("capture group 1 exists").as_str(); // safety: RE_TIER_HINT has group 1
|
||||
let tier = match tier_str.to_lowercase().as_str() {
|
||||
"flash" => Tier::Flash,
|
||||
"standard" => Tier::Standard,
|
||||
@@ -758,7 +758,8 @@ impl SmartRoutingProvider {
|
||||
|
||||
// Highest priority: explicit tier hints (e.g. "[tier:flash]")
|
||||
if let Some(caps) = RE_TIER_HINT.captures(last_user_msg) {
|
||||
let tier_str = caps.get(1).expect("capture group 1 exists").as_str();
|
||||
// SAFETY: RE_TIER_HINT has exactly one capture group; get(1) is guaranteed Some after match.
|
||||
let tier_str = caps.get(1).expect("capture group 1 exists").as_str(); // safety: RE_TIER_HINT has group 1
|
||||
let tier = match tier_str.to_lowercase().as_str() {
|
||||
"flash" => Tier::Flash,
|
||||
"standard" => Tier::Standard,
|
||||
|
||||
Reference in New Issue
Block a user