How to Configure Baseline Glob Rules for Drift-Tolerant Suppression in SkillSpector
SkillSpector enables durable false-positive filtering through YAML-based glob rules that match findings by pattern rather than exact line hashes, allowing suppressions to persist across code edits without manual baseline updates.
SkillSpector, NVIDIA's open-source skill security analyzer, provides a sophisticated suppression system that survives code refactoring. Configuring baseline glob rules for drift-tolerant suppression allows security teams to silence recurring false positives using pattern matching instead of brittle line-specific fingerprints, significantly reducing maintenance overhead as skills evolve.
Understanding the Baseline File Structure
A baseline file contains two distinct suppression mechanisms. The rules section houses drift-tolerant glob-based suppressions, while the fingerprints section stores exact hash-based suppressions that bind to specific line content. Unlike fingerprints, glob rules remain effective when line numbers shift or message text changes slightly during development.
Rule Matching Fields
Each rule in the rules array is a YAML object supporting these optional fields:
- id or rule_id: Glob pattern matching
Finding.rule_id(supports*and?wildcards) - path or file: Glob pattern matching the file path;
**normalizes to*for cross-platform compatibility - message: Case-insensitive glob matching
Finding.message; wrap keywords in*for substring matching - reason: Human-readable justification stored in audit trails and reports
A rule matches a finding only when every specified field matches the corresponding finding attribute. Unspecified fields act as wildcards, so a rule defining only id suppresses that rule ID globally across the entire codebase.
Implementation in the Suppression Engine
The suppression logic resides in src/skillspector/suppression.py.
The SuppressionRule dataclass implements the matches() method, which validates each populated field using case-insensitive fnmatch comparisons (lines 10-25). The helper _match_glob() normalizes ** to * and performs platform-agnostic pattern matching (lines 72-83).
When evaluating findings against the baseline, Baseline.reason_for() iterates through all loaded rules and returns the first matching rule's reason string (lines 50-58). If no glob rule matches, the system falls back to fingerprint comparison for exact suppression.
During the analysis pipeline, src/skillspector/nodes/report.py loads the baseline and invokes partition_findings() (lines 26-46) to segregate findings into kept and suppressed lists before SARIF generation and risk score calculation.
Configuring and Using Baseline Rules
Creating a Drift-Tolerant Baseline
Create a .skillspector-baseline.yaml file with glob rules that survive code edits:
version: 1
rules:
- id: "SQP-1"
reason: "Trigger-phrase breadth is a description nit, not a vulnerability"
- id: "SSD-2"
path: "*deploy-topology*/SKILL.md"
message: "*run the exploit*"
reason: "False positive: benign lab-test phrase"
fingerprints: []
CLI Commands
Generate baselines and apply drift-tolerant suppression via the command line:
# Create baseline with current findings stored as fingerprints
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
# Scan applying drift-tolerant glob rules
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
# Include suppressed findings in output for security auditing
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed
Python API Integration
Apply suppression rules programmatically in custom workflows:
from pathlib import Path
from skillspector.suppression import load_baseline, partition_findings
baseline = load_baseline(Path(".skillspector-baseline.yaml"))
kept, suppressed = partition_findings(findings_list, baseline)
for item in suppressed:
print(f"Suppressed {item.finding.rule_id}: {item.reason}")
Summary
- Baseline glob rules provide pattern-based suppression that survives code edits and line number shifts.
- Rules match on
id,path, andmessageusing case-insensitive glob patterns implemented viafnmatch. - The
SuppressionRuleclass in suppression.py handles drift-tolerant matching, whilepartition_findings()splits findings into kept and suppressed sets. - Use
--baselinein the CLI to apply rules; suppressed findings are excluded from risk scores and SARIF output unless using--show-suppressed.
Frequently Asked Questions
What makes glob rules "drift-tolerant" compared to fingerprints?
Fingerprint suppression relies on exact content hashes that invalidate when lines shift or text changes. Glob rules match patterns such as *run the exploit* in the message field or **/test-*/SKILL.md in the path field, remaining valid even when line numbers move or surrounding text evolves, because they match structural patterns rather than byte-level identity.
Can I combine glob rules and fingerprints in the same baseline?
Yes. The baseline file supports concurrent rules and fingerprints sections. SkillSpector checks glob rules first via Baseline.reason_for(), then falls back to fingerprint matching. This allows drift-tolerant patterns for recurring false positives while reserving exact fingerprints for specific one-off suppressions that should not match similar findings elsewhere.
How does case-insensitive matching work in message globs?
The _match_glob() helper in suppression.py normalizes both the pattern and finding message text to lowercase before applying fnmatch, ensuring that *Exploit* matches "exploit", "EXPLOIT", or "Exploit" without requiring multiple rule variations or complex regex syntax.
Where are suppressed findings filtered in the analysis pipeline?
The report node in src/skillspector/nodes/report.py loads the baseline during scan initialization and calls partition_findings() from suppression.py to bifurcate findings into kept and suppressed lists. This filtering occurs after rule evaluation but before SARIF serialization and risk score aggregation, ensuring suppressed items do not influence the final security assessment.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →