Files
wehub-resource-sync 2114ccd278
CI / Lint & Test (Python 3.13) (push) Failing after 2s
CI / Lint & Test (Python 3.14) (push) Failing after 1s
CI / Lint & Test (Python 3.12) (push) Failing after 2s
CI / DCO Check (push) Has been skipped
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:23:39 +08:00

249 lines
8.3 KiB
Python

# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for baseline / false-positive suppression."""
from __future__ import annotations
from pathlib import Path
import pytest
import yaml
from skillspector.models import Finding
from skillspector.suppression import (
Baseline,
SuppressionRule,
baseline_from_dict,
build_baseline_dict,
dump_baseline,
finding_fingerprint,
load_baseline,
partition_findings,
)
def _finding(
rule_id: str = "SQP-1",
file: str = "skill-a/SKILL.md",
message: str = "Overly broad trigger phrases",
severity: str = "MEDIUM",
start_line: int = 3,
) -> Finding:
return Finding(
rule_id=rule_id,
message=message,
severity=severity,
confidence=0.7,
file=file,
start_line=start_line,
)
# --- fingerprint --------------------------------------------------------------
def test_fingerprint_is_stable_and_prefixed() -> None:
f = _finding()
assert finding_fingerprint(f) == finding_fingerprint(_finding())
assert finding_fingerprint(f).startswith("sha256:")
def test_fingerprint_differs_on_field_change() -> None:
base = finding_fingerprint(_finding())
assert finding_fingerprint(_finding(rule_id="SQP-2")) != base
assert finding_fingerprint(_finding(file="skill-b/SKILL.md")) != base
assert finding_fingerprint(_finding(start_line=99)) != base
# --- rule matching ------------------------------------------------------------
def test_rule_matches_exact_rule_id() -> None:
rule = SuppressionRule(rule_id="SQP-1", reason="nit")
assert rule.matches(_finding(rule_id="SQP-1"))
assert not rule.matches(_finding(rule_id="SQP-2"))
def test_rule_matches_glob_rule_id() -> None:
rule = SuppressionRule(rule_id="SQP-*", reason="all quality-policy nits")
assert rule.matches(_finding(rule_id="SQP-1"))
assert rule.matches(_finding(rule_id="SQP-12"))
assert not rule.matches(_finding(rule_id="SDI-2"))
def test_rule_scoped_by_path_and_rule_id() -> None:
rule = SuppressionRule(rule_id="SSD-2", path="*deploy-topology*/SKILL.md", reason="lab phrase")
assert rule.matches(_finding(rule_id="SSD-2", file="deploy-topology-execute-scripts/SKILL.md"))
# Right rule, wrong file -> not suppressed
assert not rule.matches(_finding(rule_id="SSD-2", file="other/SKILL.md"))
# Right file, wrong rule -> not suppressed
assert not rule.matches(
_finding(rule_id="SQP-1", file="deploy-topology-execute-scripts/SKILL.md")
)
def test_rule_message_glob_is_case_insensitive_substring() -> None:
rule = SuppressionRule(message="*telemetry*", reason="first-party telemetry")
assert rule.matches(_finding(message="Mandates completion TELEMETRY call"))
assert not rule.matches(_finding(message="Reads environment variables"))
def test_double_star_is_alias_for_star() -> None:
rule = SuppressionRule(path="**/SKILL.md", reason="any skill file")
assert rule.matches(_finding(file="a/b/c/SKILL.md"))
def test_empty_rule_never_matches() -> None:
assert not SuppressionRule().matches(_finding())
# --- Baseline.reason_for ------------------------------------------------------
def test_baseline_reason_for_rule_then_fingerprint() -> None:
f = _finding()
by_rule = Baseline(rules=[SuppressionRule(rule_id="SQP-1", reason="rule wins")])
assert by_rule.reason_for(f) == "rule wins"
by_fp = Baseline(fingerprints={finding_fingerprint(f): "fp reason"})
assert by_fp.reason_for(f) == "fp reason"
assert Baseline().reason_for(f) is None
def test_baseline_default_reason_when_blank() -> None:
f = _finding()
assert Baseline(rules=[SuppressionRule(rule_id="SQP-1")]).reason_for(f) == (
"matched suppression rule"
)
assert Baseline(fingerprints={finding_fingerprint(f): ""}).reason_for(f) == (
"matched baseline fingerprint"
)
# --- partition_findings -------------------------------------------------------
def test_partition_no_baseline_keeps_all() -> None:
findings = [_finding(), _finding(rule_id="SDI-2")]
kept, suppressed = partition_findings(findings, None)
assert kept == findings
assert suppressed == []
def test_partition_empty_baseline_keeps_all() -> None:
findings = [_finding()]
kept, suppressed = partition_findings(findings, Baseline())
assert len(kept) == 1
assert suppressed == []
def test_partition_splits_and_records_reason() -> None:
keep = _finding(rule_id="SDI-2", message="real issue")
drop = _finding(rule_id="SQP-1")
baseline = Baseline(rules=[SuppressionRule(rule_id="SQP-1", reason="fp")])
kept, suppressed = partition_findings([keep, drop], baseline)
assert kept == [keep]
assert len(suppressed) == 1
assert suppressed[0].finding is drop
assert suppressed[0].reason == "fp"
def test_suppressed_finding_to_dict() -> None:
baseline = Baseline(rules=[SuppressionRule(rule_id="SQP-1", reason="fp")])
_, suppressed = partition_findings([_finding()], baseline)
d = suppressed[0].to_dict()
assert d["suppressed"] is True
assert d["suppression_reason"] == "fp"
assert d["id"] == "SQP-1"
# --- baseline_from_dict parsing ----------------------------------------------
def test_baseline_from_dict_full() -> None:
data = {
"version": 1,
"rules": [
{"id": "SQP-*", "reason": "nits"},
{"rule_id": "SSD-2", "file": "*/SKILL.md", "message": "*exploit*", "reason": "fp"},
],
"fingerprints": [
"sha256:deadbeefdeadbeef",
{"hash": "sha256:cafebabecafebabe", "reason": "accepted"},
],
}
baseline = baseline_from_dict(data)
assert len(baseline.rules) == 2
assert baseline.rules[1].path == "*/SKILL.md"
assert baseline.fingerprints["sha256:deadbeefdeadbeef"] == ""
assert baseline.fingerprints["sha256:cafebabecafebabe"] == "accepted"
def test_baseline_from_dict_rejects_all_wildcard_rule() -> None:
with pytest.raises(ValueError, match="at least one of"):
baseline_from_dict({"rules": [{"reason": "oops, suppresses everything"}]})
def test_baseline_from_dict_rejects_non_mapping() -> None:
with pytest.raises(ValueError):
baseline_from_dict(["not", "a", "mapping"]) # type: ignore[arg-type]
# --- load / dump round-trip ---------------------------------------------------
def test_load_baseline_missing_file(tmp_path: Path) -> None:
with pytest.raises(FileNotFoundError):
load_baseline(tmp_path / "nope.yaml")
def test_build_dump_load_round_trip(tmp_path: Path) -> None:
findings = [_finding(), _finding(rule_id="SDI-2", file="x/SKILL.md")]
data = build_baseline_dict(findings, reason="accepted in CI")
out = tmp_path / "baseline.yaml"
dump_baseline(data, out)
assert out.exists()
baseline = load_baseline(out)
# Every original finding is now suppressed by fingerprint.
kept, suppressed = partition_findings(findings, baseline)
assert kept == []
assert len(suppressed) == 2
assert all(sf.reason == "accepted in CI" for sf in suppressed)
def test_dump_baseline_json_extension(tmp_path: Path) -> None:
data = build_baseline_dict([_finding()])
out = tmp_path / "baseline.json"
dump_baseline(data, out)
# Valid JSON and loadable back through the YAML-or-JSON loader.
import json
parsed = json.loads(out.read_text())
assert parsed["version"] == 1
assert load_baseline(out).fingerprints
def test_load_baseline_parses_yaml_content(tmp_path: Path) -> None:
out = tmp_path / "b.yaml"
out.write_text(
yaml.safe_dump({"version": 1, "rules": [{"id": "SQP-1", "reason": "r"}]}),
encoding="utf-8",
)
baseline = load_baseline(out)
assert baseline.rules[0].rule_id == "SQP-1"