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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/.gitattributes text eol=lf
.github/workflows/*.yml text eol=lf
tools/sbom-diff-and-risk/examples/*.yml text eol=lf
*.json text eol=lf
*.md text eol=lf
*.py text eol=lf
Expand Down
16 changes: 16 additions & 0 deletions scripts/validate-reviewer-routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Path("docs/repo-scope-map.md"),
Path("docs/risk-model-boundary.md"),
Path("tools/sbom-diff-and-risk/docs/report-schema.md"),
Path("tools/sbom-diff-and-risk/docs/github-actions-consumer-example.md"),
Path("tools/sbom-diff-and-risk/docs/reviewer-path.md"),
Path("projects/precipitation-anomaly-diagnostics/docs/reviewer-path.md"),
Path("projects/precipitation-anomaly-diagnostics-lab/docs/reviewer-path.md"),
Expand Down Expand Up @@ -77,10 +78,15 @@
"tools/sbom-diff-and-risk/examples/sample-report.json",
"tools/sbom-diff-and-risk/examples/sample-summary.json",
},
Path("tools/sbom-diff-and-risk/docs/github-actions-consumer-example.md"): {
"tools/sbom-diff-and-risk/docs/policy-decision-ci-cookbook.md",
"tools/sbom-diff-and-risk/examples/github-actions-policy-consumer.yml",
},
Path("tools/sbom-diff-and-risk/docs/reviewer-path.md"): {
".github/workflows/reviewer-route-contract-ci.yml",
"docs/risk-model-boundary.md",
"scripts/validate-reviewer-routes.py",
"tools/sbom-diff-and-risk/examples/github-actions-policy-consumer.yml",
"tools/sbom-diff-and-risk/docs/reviewer-brief.md",
"tools/sbom-diff-and-risk/docs/reviewer-evidence-pack.md",
"tools/sbom-diff-and-risk/docs/verification.md",
Expand Down Expand Up @@ -189,6 +195,15 @@
"not a package safety verdict",
"not a CVE result",
),
Path("tools/sbom-diff-and-risk/docs/github-actions-consumer-example.md"): (
"minimal GitHub Actions consumer workflow",
"outputs/policy.json",
"Upload policy JSON",
"Pass or fail based on local policy",
"tool's own exit code",
"not a CVE scanner",
"not a dependency safety oracle",
),
Path("tools/sbom-diff-and-risk/docs/reviewer-path.md"): (
"Artifact evidence map",
"Reviewer route contract",
Expand All @@ -202,6 +217,7 @@
"python scripts/validate-reviewer-routes.py",
"No network",
"summary.evidence_confidence",
"runs the tool, uploads `policy.json`, and fails or passes from the policy exit code",
"not current PyPI package truth",
"not current repository reputation",
"It does not decide whether a dependency is safe.",
Expand Down
3 changes: 1 addition & 2 deletions tools/sbom-diff-and-risk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,7 @@ The [examples/](examples/) directory includes:
- a Scorecard-aware policy example at `examples/policy-scorecard-minimal.yml`
- a sample pass JSON report at [sample-report.json](examples/sample-report.json)
- a sample summary-only JSON artifact at [sample-summary.json](examples/sample-summary.json)
- a consumer GitHub Actions workflow example at [github-actions-consumer.yml](examples/github-actions-consumer.yml)
- a policy-gated consumer GitHub Actions workflow example at [github-actions-policy-consumer.yml](examples/github-actions-policy-consumer.yml)
- a minimal policy-gated consumer GitHub Actions workflow example at [github-actions-policy-consumer.yml](examples/github-actions-policy-consumer.yml)
- a sample pass Markdown report at [sample-report.md](examples/sample-report.md)
- sample policy-warn reports at [sample-policy-warn-report.json](examples/sample-policy-warn-report.json) and [sample-policy-warn-report.md](examples/sample-policy-warn-report.md)
- sample policy-fail reports at [sample-policy-fail-report.json](examples/sample-policy-fail-report.json) and [sample-policy-fail-report.md](examples/sample-policy-fail-report.md)
Expand Down
106 changes: 43 additions & 63 deletions tools/sbom-diff-and-risk/docs/github-actions-consumer-example.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# GitHub Actions consumer example
# GitHub Actions policy consumer demo

This page shows how another repository could run `sbom-diff-risk` from GitHub
Actions and upload the generated review artifacts.
This page documents the minimal GitHub Actions consumer workflow for
`sbom-diff-risk`. The workflow runs the tool with a local policy, uploads
`outputs/policy.json`, and then passes or fails based on the tool's policy exit
code.

It is documentation only. It is not a workflow for this repository, and it does
not change the `sbom-diff-risk` CLI or publishing model.
Expand All @@ -10,24 +12,15 @@ Production PyPI publishing is intentionally deferred, so consumers should not
install `sbom-diff-and-risk` from production PyPI. Use a GitHub Release asset or
a local checkout instead.

## Example workflow
## Minimal policy workflow

This example downloads the released wheel from the public GitHub Release, runs a
local comparison, writes JSON, Markdown, summary JSON, and SARIF outputs, applies
an explicit local threshold to `summary.json`, and uploads the outputs as CI
artifacts.

Replace the placeholder input paths with files from the consumer repository.
The same workflow is also checked in as
[../examples/github-actions-consumer.yml](../examples/github-actions-consumer.yml)
Replace the placeholder input and policy paths with files from the consumer
repository. The same workflow is checked in as
[../examples/github-actions-policy-consumer.yml](../examples/github-actions-policy-consumer.yml)
for copying into consumer repositories.

For a policy-gated variant that writes `outputs/policy.json` with
`--policy-json PATH`, see
[../examples/github-actions-policy-consumer.yml](../examples/github-actions-policy-consumer.yml).

```yaml
name: Dependency diff review
name: Dependency policy review

on:
pull_request:
Expand All @@ -37,7 +30,7 @@ permissions:
contents: read

jobs:
dependency-diff:
dependency-policy:
runs-on: ubuntu-latest

steps:
Expand All @@ -64,50 +57,42 @@ jobs:
python -m pip install \
.tooling/sbom-diff-risk/sbom_diff_and_risk-0.9.0-py3-none-any.whl

- name: Compare dependency evidence
- name: Run dependency policy
id: compare
shell: bash
run: |
mkdir -p outputs
set +e
sbom-diff-risk compare \
--before path/to/before-sbom.json \
--after path/to/after-sbom.json \
--format auto \
--out-json outputs/report.json \
--out-md outputs/report.md \
--summary-json outputs/summary.json \
--out-sarif outputs/report.sarif

- name: Apply local summary threshold
run: |
python - <<'PY'
import json
from pathlib import Path

summary = json.loads(
Path("outputs/summary.json").read_text(encoding="utf-8")
)
risk_counts = summary["risk_counts"]

max_new_packages = 2
new_package_count = risk_counts.get("new_package", 0)
print(f"new_package={new_package_count}")

if new_package_count > max_new_packages:
raise SystemExit(
f"new_package count exceeds local threshold: {max_new_packages}"
)
PY

- name: Upload dependency diff outputs
--policy path/to/policy.yml \
--policy-json outputs/policy.json
status=$?
set -e
echo "exit_code=$status" >> "$GITHUB_OUTPUT"

- name: Upload policy JSON
if: always()
uses: actions/upload-artifact@v7
with:
name: dependency-diff-outputs
path: |
outputs/report.json
outputs/report.md
outputs/summary.json
outputs/report.sarif
name: dependency-policy-json
path: outputs/policy.json
if-no-files-found: error

- name: Pass or fail based on local policy
run: exit "${{ steps.compare.outputs.exit_code }}"
```

The upload step runs before the final pass/fail step, so reviewers can inspect
`outputs/policy.json` even when the local policy blocks the job. The final step
uses the tool's own exit code:

- `0`: report written and local policy passed
- `1`: report written and local policy produced blocking findings
- `2`: usage, parse, or runtime error before a successful policy decision

## Local checkout variant

If the consumer repository vendors or checks out this toolkit repository, install
Expand All @@ -120,17 +105,14 @@ from that local checkout instead of downloading a release wheel:
path/to/scientific-computing-toolkit/tools/sbom-diff-and-risk
```

## What the example proves
## What the demo proves

- The consumer workflow runs deterministic local diff analysis over files the
- The consumer workflow runs deterministic local policy analysis over files the
consumer repository provides.
- `outputs/report.json` contains the full machine-readable report.
- `outputs/report.md` contains the human-readable review report.
- `outputs/summary.json` contains the same object as `report.json["summary"]`.
- `outputs/report.sarif` can be uploaded or inspected by consumers that want
SARIF output.
- The threshold step is a local consumer policy choice, not a built-in security
verdict.
- `outputs/policy.json` contains policy status, blocking/warning/suppressed
findings, and rule metadata.
- CI pass/fail is based on the `sbom-diff-risk compare` exit code.
- The workflow does not invent a second policy decision after the tool runs.

## Boundaries

Expand All @@ -145,7 +127,5 @@ from that local checkout instead of downloading a release wheel:
- Replace all placeholder input paths with non-private paths from the consumer
repository.

For compact summary consumption patterns, see
[summary-json-ci-cookbook.md](summary-json-ci-cookbook.md).
For policy sidecar consumption patterns, see
[policy-decision-ci-cookbook.md](policy-decision-ci-cookbook.md).
6 changes: 3 additions & 3 deletions tools/sbom-diff-and-risk/docs/policy-decision-ci-cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ For compact consumer examples that distinguish `pass`, `warn`, `fail`, and
`needs-review` review outcomes, see
[examples/policy-decisions](../examples/policy-decisions/README.md).

For a full GitHub Actions consumer workflow example that captures
`outputs/policy.json`, uploads it even when local policy fails, and then fails
the job based on `summary.policy`, see
For a minimal GitHub Actions consumer workflow example that captures
`outputs/policy.json`, uploads it before the final pass/fail step, and then
uses the tool's exit code as the CI result, see
[github-actions-policy-consumer.yml](../examples/github-actions-policy-consumer.yml).

## Python consumer
Expand Down
Loading