Repository navigation
feat(detection): per-request scan time budget (detection_max_scan_seconds) - #139
Merged
Merged
Conversation
…onds) Port of the guard-core reference budget (guard-core #167). The summed regex scan CPU time of one request is capped, checked between patterns, and a spent budget records a weighted pattern_timeout threat named scan_time_budget_exhausted. The thread CPU clock goes through the safe rustix wrapper because the engine forbids unsafe.
…old rule The budget threat is an ordinary weighted regex-side threat in the reference, so scan_request no longer blocks on it regardless of detection_threat_score_threshold. is_threat follows the threshold rule, and a threat value is reported with the budget reason without the category filter dropping it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #138
I am porting the per-request scan time budget from guard-core (Guard-Core/guard-core #167) to the Rust engine. The TypeScript port is guard-core-ts #132 and the JVM port is guard-core-jvm #53.
SecurityConfig::detection_max_scan_seconds: default 10.0, valid 0.1 to 60, validated with the other bounds.pattern_timeoutnamedscan_time_budget_exhausted(empty match, position 0, categorycustom, weight 1.0), exposed as the newThreat::PatternTimeout.scan_requestshares one budget across all values of the request and reports a threat value with the reasonPattern exceeded scan time budget: 'scan_time_budget_exhausted'. The budget threat is an ordinary weighted threat, sois_threatfollows the normaldetection_threat_score_thresholdrule exactly like the reference (a threshold above 1.0 leaves a budget-only value clean), and the enabled-category filter does not drop it. When a value already matched an enabled category the reason keeps it and appends the budget text, the way the reference_build_threats_messagedoes.Where the cap lives
DetectConfigis unchanged. The cap rides onDetectionExclusionConfig::max_scan_seconds(Option<f64>,Noneis the default of 10.0) andResolvedExclusions::max_scan_seconds, the engine's port of the referencedetection_config.pyresolvers. A newDetectConfigfield would break every adapter'sDetectConfigliteral on master and turn the ecosystem gate red, whereas the adapters already buildDetectionExclusionConfigwith..Default::default(), as the semantic header opt-out did in #137.detecton its own gives each call a fresh default budget, anddetect_with_budgettakes a caller-ownedScanTimeBudget.The CPU clock
The engine crate has
unsafe_code = "forbid"(crates/guard-core-engine/Cargo.toml), so a directlibc::clock_gettimecall is not possible, althoughlibcis already in the engine's tree (throughcpufeaturesandgetrandom). I used the saferustix::time::clock_gettime(ClockId::ThreadCPUTime)wrapper, declared only for Linux, Android and macOS.rustixwas inCargo.lockalready (throughtempfile, for the rocket example) but not in the engine's tree, so this adds one direct dependency for those targets, and the lock gains one line. Other targets fall back to wall time, which can only exhaust the budget earlier, never later.cargo deny checkandcargo auditpass.Compatibility
Threatgains thePatternTimeoutvariant, so exhaustive matches need an arm (none of the four adapters matches onThreat).DetectionExclusionConfigandResolvedExclusionsno longer deriveEq(they carry anf64), andResolvedExclusionsgains a public field.Tests
The new tests failed to compile on master (
no variant ... named PatternTimeout,cannot find function detect_with_budget,no field detection_max_scan_seconds on type SecurityConfig) and pass now. They cover the field default and the 0.1 to 60 range, the exact threat shape, a budget shared across values, an unchanged result within budget, the reason naming the budget, the budget threat reported under a category filter and not blocking above a 1.0 threshold, and the real thread clock advancing.I ran everything
ci.ymlruns: fmt, both clippy variants with-D warnings,cargo test --workspace, ledger, conformance and pipeline conformance gates,cargo docwith-D warnings, MSRV 1.92 check and test,cargo deny,cargo audit, and the 100% line coverage gate (49232/49232). The adapters wire the field through in their own PRs, which need this one merged first.