Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tools/sbom-diff-and-risk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ machine-readable JSON output shape, see
[docs/report-schema.md](docs/report-schema.md). For policy decision
explainability fields, see
[docs/policy-decision-explainability.md](docs/policy-decision-explainability.md).
For CI consumption of policy decision fields, see
[docs/policy-decision-ci-cookbook.md](docs/policy-decision-ci-cookbook.md).
For CI consumption of summary-only output, see
[docs/summary-json-ci-cookbook.md](docs/summary-json-ci-cookbook.md).
For a consumer-facing GitHub Actions example, see
Expand Down
133 changes: 133 additions & 0 deletions tools/sbom-diff-and-risk/docs/policy-decision-ci-cookbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Policy decision CI cookbook

This page shows how to consume policy decision explanation fields from
`report.json` in CI without changing the `sbom-diff-risk` analysis model.

Use this when a repository wants a small job summary that explains local policy
blocks, warnings, or suppressions in machine-readable terms.

## Minimal command

```bash
sbom-diff-risk compare \
--before examples/cdx_before.json \
--after examples/cdx_after.json \
--policy examples/policy-strict.yml \
--out-json outputs/policy-report.json
```

The strict example policy can make the command return a policy failure exit
code. In CI, keep the generated `outputs/policy-report.json` artifact so the
policy decision metadata remains available for review.

## Python consumer

This example reads the full JSON report, prints compact policy status, and then
prints the stable explanation fields for blocking and warning findings.

```python
import json
from pathlib import Path

report = json.loads(
Path("outputs/policy-report.json").read_text(encoding="utf-8")
)

policy = report.get("summary", {}).get("policy")
if policy is None:
print("policy=not-used")
raise SystemExit(0)

print(
"policy="
f"{policy['status']} "
f"blocking={policy['blocking']} "
f"warning={policy['warning']} "
f"suppressed={policy['suppressed']}"
)

findings = (
report.get("blocking_findings", [])
+ report.get("warning_findings", [])
+ report.get("suppressed_findings", [])
)

for finding in findings:
print(
"policy-finding "
f"level={finding.get('level')} "
f"rule={finding.get('policy_rule')} "
f"reason={finding.get('decision_reason')} "
f"severity_source={finding.get('severity_source')} "
f"observed={finding.get('observed_value')} "
f"threshold={finding.get('matched_threshold')}"
)

if policy["status"] == "fail":
raise SystemExit("local policy failed")
```

The final failure is based on the local policy status already produced by the
tool. The snippet does not create a new package safety verdict.

## PowerShell consumer

This example uses `ConvertFrom-Json` to print the same policy status and
explanation fields.

```powershell
$report = Get-Content outputs/policy-report.json -Raw | ConvertFrom-Json
$policy = $report.summary.policy

if ($null -eq $policy) {
Write-Output "policy=not-used"
exit 0
}

Write-Output (
"policy={0} blocking={1} warning={2} suppressed={3}" -f
$policy.status,
$policy.blocking,
$policy.warning,
$policy.suppressed
)

$findings = @()
$findings += @($report.blocking_findings)
$findings += @($report.warning_findings)
$findings += @($report.suppressed_findings)

foreach ($finding in $findings) {
Write-Output (
"policy-finding level={0} rule={1} reason={2} severity_source={3} observed={4} threshold={5}" -f
$finding.level,
$finding.policy_rule,
$finding.decision_reason,
$finding.severity_source,
$finding.observed_value,
$finding.matched_threshold
)
}

if ($policy.status -eq "fail") {
throw "local policy failed"
}
```

## Compatibility notes

- `summary.policy` appears only when policy evaluation is applied.
- Policy decision explanation fields appear only on policy finding objects.
- `risks` remains the local heuristic finding list; use policy finding sections
when you need policy-decision metadata.
- Consumers should treat unrecognized future fields as additive report data.
- Use `summary.policy` for compact status and counts.
- Use policy finding explanation fields for reviewer-facing detail.

## Non-claims

- The policy decision fields are not CVE results.
- The policy decision fields are not dependency safety verdicts.
- The snippets do not add network behavior.
- The snippets do not replace human review of local policy choices.
- Production PyPI publishing remains intentionally deferred.
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@ the matching rule was active through `warn_on`.
## CI and review usage

Consumers can use these fields to group policy findings by rule, explain why a
local gate failed, or build small job summaries. For example, a CI step can read
`blocking_findings`, print each `policy_rule` and `decision_reason`, and fail
only because the tool already returned a policy failure exit code.
local gate failed, or build small job summaries. For CI examples, see
[policy-decision-ci-cookbook.md](policy-decision-ci-cookbook.md).

Use `summary.policy` for compact counts and status. Use policy finding
explanation fields when a reviewer needs to inspect why the status was
Expand Down
4 changes: 3 additions & 1 deletion tools/sbom-diff-and-risk/docs/report-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ policy-decision metadata unless a policy evaluation maps them into policy
findings.

For reviewer-facing examples and interpretation guidance, see
[policy-decision-explainability.md](policy-decision-explainability.md).
[policy-decision-explainability.md](policy-decision-explainability.md). For CI
consumer snippets, see
[policy-decision-ci-cookbook.md](policy-decision-ci-cookbook.md).

## Summary contract

Expand Down
3 changes: 3 additions & 0 deletions tools/sbom-diff-and-risk/docs/reviewer-evidence-pack.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ For policy finding interpretation, see
documents the policy decision metadata used to explain local blocks, warnings,
and suppressions.

For CI job-summary examples that consume policy decision metadata, see
[policy-decision-ci-cookbook.md](policy-decision-ci-cookbook.md).

For CI dashboard, job-summary, and local-threshold examples that consume
`outputs/summary.json`, see
[summary-json-ci-cookbook.md](summary-json-ci-cookbook.md).
Expand Down
4 changes: 4 additions & 0 deletions tools/sbom-diff-and-risk/docs/summary-json-ci-cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ sbom-diff-risk compare \
The full report remains available at `outputs/report.json`. The compact
summary-only object is written to `outputs/summary.json`.

For CI examples that consume detailed policy decision explanation fields from
the full JSON report, see
[policy-decision-ci-cookbook.md](policy-decision-ci-cookbook.md).

## Python consumer

This example reads the summary and applies an explicit local threshold. The
Expand Down