mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-18 00:47:23 +02:00
ci: add reproducible supply-chain gates
This commit is contained in:
@@ -45,3 +45,27 @@ def test_actionlint_version_and_checksum_match_manifest():
|
||||
|
||||
assert f'ACTIONLINT_VERSION: "{version.removeprefix("v")}"' in workflow
|
||||
assert f'ACTIONLINT_SHA256: "{pin.removeprefix("sha256:")}"' in workflow
|
||||
|
||||
|
||||
def test_uv_and_gitleaks_pins_match_manifest():
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8")
|
||||
entries = _manifest_entries()
|
||||
uv_pin, uv_version = entries[("tool", "astral-sh/uv")]
|
||||
gitleaks_pin, gitleaks_version = entries[("tool", "gitleaks/gitleaks")]
|
||||
|
||||
assert uv_pin == f"pypi:{uv_version.removeprefix('v')}"
|
||||
assert f'UV_VERSION: "{uv_version.removeprefix("v")}"' in workflow
|
||||
assert f'GITLEAKS_VERSION: "{gitleaks_version.removeprefix("v")}"' in workflow
|
||||
assert f'GITLEAKS_SHA256: "{gitleaks_pin.removeprefix("sha256:")}"' in workflow
|
||||
|
||||
|
||||
def test_ci_requires_the_committed_lock_and_strict_policy_gate():
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8")
|
||||
|
||||
assert "uv lock --check" in workflow
|
||||
assert "uv sync --locked" in workflow
|
||||
assert "scripts/check_supply_chain_policy.py audit" in workflow
|
||||
assert "scripts/check_supply_chain_policy.py secrets" in workflow
|
||||
assert "scripts/check_supply_chain_policy.py licenses" in workflow
|
||||
supply_chain_job = workflow.split(" supply-chain:\n", maxsplit=1)[1]
|
||||
assert "|| true" not in supply_chain_job
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
"""Tests for reproducible supply-chain policy decisions."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).parents[1]
|
||||
SCRIPT = ROOT / "scripts" / "check_supply_chain_policy.py"
|
||||
SPEC = importlib.util.spec_from_file_location("check_supply_chain_policy", SCRIPT)
|
||||
assert SPEC is not None and SPEC.loader is not None
|
||||
MODULE = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(MODULE)
|
||||
|
||||
|
||||
def _policy() -> dict[str, object]:
|
||||
return {
|
||||
"schema_version": 1,
|
||||
"vulnerability": {
|
||||
"fail_severities": ["unknown", "low", "medium", "high", "critical"],
|
||||
"max_fixed_suppression_days": 7,
|
||||
"max_unfixed_suppression_days": 90,
|
||||
"suppressions": [],
|
||||
},
|
||||
"secret": {
|
||||
"report_redaction_percent": 100,
|
||||
"max_suppression_days": 30,
|
||||
"suppressions": [],
|
||||
},
|
||||
"license": {
|
||||
"allowed_expressions": ["MIT"],
|
||||
"excluded_packages": ["obliteratus"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_committed_policy_is_valid():
|
||||
policy = MODULE._read_json(ROOT / "ci" / "supply-chain-policy.json")
|
||||
assert MODULE.validate_policy(policy) == []
|
||||
|
||||
|
||||
def test_policy_rejects_expired_and_overlong_suppressions():
|
||||
policy = _policy()
|
||||
policy["vulnerability"]["suppressions"] = [
|
||||
{
|
||||
"id": "GHSA-example",
|
||||
"reason": "temporary",
|
||||
"approved_on": "2026-01-01",
|
||||
"expires": "2026-01-10",
|
||||
"fix_available": True,
|
||||
},
|
||||
]
|
||||
failures = MODULE.validate_policy(policy, today=date(2026, 1, 11))
|
||||
|
||||
assert "suppression[0] expired on 2026-01-10" in failures
|
||||
assert "suppression[0] exceeds its 7-day maximum" in failures
|
||||
|
||||
|
||||
def test_audit_blocks_every_unsuppressed_vulnerability():
|
||||
evidence = {
|
||||
"vulnerabilities": [
|
||||
{"id": "GHSA-example", "aliases": ["CVE-example"], "fix_versions": ["2.0"]},
|
||||
],
|
||||
"adverse_statuses": [],
|
||||
}
|
||||
decision = MODULE.evaluate_audit(_policy(), evidence, scanner_status=1)
|
||||
|
||||
assert decision["passed"] is False
|
||||
assert decision["failures"] == ["unsuppressed vulnerability: GHSA-example"]
|
||||
|
||||
|
||||
def test_audit_rejects_unexplained_scanner_failure():
|
||||
evidence = {"vulnerabilities": [], "adverse_statuses": []}
|
||||
|
||||
decision = MODULE.evaluate_audit(_policy(), evidence, scanner_status=1)
|
||||
|
||||
assert decision["passed"] is False
|
||||
assert decision["failures"] == [
|
||||
"uv audit returned failure without reviewable findings",
|
||||
]
|
||||
|
||||
|
||||
def test_audit_accepts_bounded_alias_suppression():
|
||||
policy = _policy()
|
||||
policy["vulnerability"]["suppressions"] = [
|
||||
{
|
||||
"id": "CVE-example",
|
||||
"reason": "upgrade lands this week",
|
||||
"approved_on": "2026-01-01",
|
||||
"expires": "2026-01-08",
|
||||
"fix_available": True,
|
||||
},
|
||||
]
|
||||
evidence = {
|
||||
"vulnerabilities": [
|
||||
{"id": "GHSA-example", "aliases": ["CVE-example"], "fix_versions": ["2.0"]},
|
||||
],
|
||||
"adverse_statuses": [],
|
||||
}
|
||||
decision = MODULE.evaluate_audit(
|
||||
policy,
|
||||
evidence,
|
||||
scanner_status=1,
|
||||
today=date(2026, 1, 2),
|
||||
)
|
||||
|
||||
assert decision["passed"] is True
|
||||
assert decision["suppressed"] == ["GHSA-example"]
|
||||
|
||||
|
||||
def test_audit_rejects_stale_fixability_claim():
|
||||
policy = _policy()
|
||||
policy["vulnerability"]["suppressions"] = [
|
||||
{
|
||||
"id": "GHSA-example",
|
||||
"reason": "waiting for a fix",
|
||||
"approved_on": "2026-01-01",
|
||||
"expires": "2026-03-01",
|
||||
"fix_available": False,
|
||||
},
|
||||
]
|
||||
evidence = {
|
||||
"vulnerabilities": [{"id": "GHSA-example", "fix_versions": ["2.0"]}],
|
||||
"adverse_statuses": [],
|
||||
}
|
||||
decision = MODULE.evaluate_audit(
|
||||
policy,
|
||||
evidence,
|
||||
scanner_status=1,
|
||||
today=date(2026, 1, 2),
|
||||
)
|
||||
|
||||
assert decision["passed"] is False
|
||||
assert any("fixability is stale" in failure for failure in decision["failures"])
|
||||
|
||||
|
||||
def test_license_gate_is_exact_and_excludes_first_party_package():
|
||||
inventory = [
|
||||
{"Name": "obliteratus", "License": "AGPL-3.0-or-later"},
|
||||
{"Name": "safe", "License": "MIT"},
|
||||
{"Name": "unknown", "License": "UNKNOWN"},
|
||||
]
|
||||
decision = MODULE.evaluate_licenses(_policy(), inventory)
|
||||
|
||||
assert decision["passed"] is False
|
||||
assert decision["checked_packages"] == 2
|
||||
assert decision["failures"] == ["unapproved license expression for unknown: UNKNOWN"]
|
||||
|
||||
|
||||
def test_secret_gate_requires_redaction_even_for_suppressed_finding():
|
||||
policy = _policy()
|
||||
policy["secret"]["suppressions"] = [
|
||||
{
|
||||
"fingerprint": "file:rule:1",
|
||||
"reason": "documented fixture",
|
||||
"approved_on": "2026-01-01",
|
||||
"expires": "2026-01-15",
|
||||
},
|
||||
]
|
||||
report = [
|
||||
{
|
||||
"Fingerprint": "file:rule:1",
|
||||
"Secret": "not-redacted",
|
||||
"Match": "token=not-redacted",
|
||||
},
|
||||
]
|
||||
decision = MODULE.evaluate_secrets(
|
||||
policy,
|
||||
report,
|
||||
scanner_status=1,
|
||||
today=date(2026, 1, 2),
|
||||
)
|
||||
|
||||
assert decision["passed"] is False
|
||||
assert any("not fully redacted" in failure for failure in decision["failures"])
|
||||
|
||||
|
||||
def test_bind_sbom_adds_exact_wheel_hash(tmp_path):
|
||||
wheel = tmp_path / "obliteratus-0.1.2-py3-none-any.whl"
|
||||
wheel.write_bytes(b"wheel")
|
||||
sbom = {
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"metadata": {"component": {"name": "obliteratus"}},
|
||||
}
|
||||
|
||||
bound = MODULE.bind_sbom(sbom, wheel)
|
||||
|
||||
component = bound["metadata"]["component"]
|
||||
assert component["hashes"] == [
|
||||
{
|
||||
"alg": "SHA-256",
|
||||
"content": "ba59926159d2aa256eb8739b8da7e2b574b960e1202c6d624cbe981cef996c91",
|
||||
},
|
||||
]
|
||||
assert component["properties"] == [
|
||||
{"name": "obliteratus:distribution-file", "value": wheel.name},
|
||||
]
|
||||
Reference in New Issue
Block a user