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, and message using case-insensitive glob patterns implemented via fnmatch.
  • The SuppressionRule class in suppression.py handles drift-tolerant matching, while partition_findings() splits findings into kept and suppressed sets.
  • Use --baseline in 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →