Skip to content

Commit 13fa0b6

Browse files
authored
[codex] Add policy decision explainability guide
Docs/example update adding policy decision explainability guidance, syncing reviewer-facing v0.7.0 references, and preserving deferred production PyPI status. No runtime, workflow, package metadata, tag, release, or publishing changes.
1 parent 9d3920a commit 13fa0b6

9 files changed

Lines changed: 218 additions & 45 deletions

tools/sbom-diff-and-risk/README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,25 @@ It uses conservative heuristics for change intelligence. By default it does not
1010

1111
This project has two different provenance stories:
1212

13-
For a concise reviewer-facing overview, start with [docs/reviewer-brief.md](docs/reviewer-brief.md). For reproducible review evidence and verification commands, use [docs/reviewer-evidence-pack.md](docs/reviewer-evidence-pack.md). For machine-readable JSON output shape, see [docs/report-schema.md](docs/report-schema.md). For CI consumption of summary-only output, see [docs/summary-json-ci-cookbook.md](docs/summary-json-ci-cookbook.md).
14-
For a consumer-facing GitHub Actions example, see [docs/github-actions-consumer-example.md](docs/github-actions-consumer-example.md).
13+
For a concise reviewer-facing overview, start with
14+
[docs/reviewer-brief.md](docs/reviewer-brief.md). For reproducible review
15+
evidence and verification commands, use
16+
[docs/reviewer-evidence-pack.md](docs/reviewer-evidence-pack.md). For
17+
machine-readable JSON output shape, see
18+
[docs/report-schema.md](docs/report-schema.md). For policy decision
19+
explainability fields, see
20+
[docs/policy-decision-explainability.md](docs/policy-decision-explainability.md).
21+
For CI consumption of summary-only output, see
22+
[docs/summary-json-ci-cookbook.md](docs/summary-json-ci-cookbook.md).
23+
For a consumer-facing GitHub Actions example, see
24+
[docs/github-actions-consumer-example.md](docs/github-actions-consumer-example.md).
1525

16-
1. If you want to verify `sbom-diff-and-risk` itself, start with [docs/verification.md](docs/verification.md).
17-
2. If you want to use `sbom-diff-and-risk` to analyze third-party dependency provenance, start with [Dependency provenance analysis](#dependency-provenance-analysis-opt-in) and [Dependency provenance reporting](#dependency-provenance-reporting).
26+
1. If you want to verify `sbom-diff-and-risk` itself, start with
27+
[docs/verification.md](docs/verification.md).
28+
2. If you want to use `sbom-diff-and-risk` to analyze third-party dependency
29+
provenance, start with
30+
[Dependency provenance analysis](#dependency-provenance-analysis-opt-in)
31+
and [Dependency provenance reporting](#dependency-provenance-reporting).
1832

1933
## Scope
2034

tools/sbom-diff-and-risk/docs/github-actions-consumer-example.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ jobs:
5050
GH_TOKEN: ${{ github.token }}
5151
run: |
5252
mkdir -p .tooling/sbom-diff-risk
53-
gh release download v0.6.0 \
53+
gh release download v0.7.0 \
5454
--repo stacknil/scientific-computing-toolkit \
55-
--pattern "sbom_diff_and_risk-0.6.0-py3-none-any.whl" \
55+
--pattern "sbom_diff_and_risk-0.7.0-py3-none-any.whl" \
5656
--dir .tooling/sbom-diff-risk
5757
5858
- name: Install sbom-diff-risk
5959
run: |
6060
python -m pip install \
61-
.tooling/sbom-diff-risk/sbom_diff_and_risk-0.6.0-py3-none-any.whl
61+
.tooling/sbom-diff-risk/sbom_diff_and_risk-0.7.0-py3-none-any.whl
6262
6363
- name: Compare dependency evidence
6464
run: |
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Policy decision explainability
2+
3+
This page explains the machine-readable policy decision metadata emitted in
4+
JSON reports. It is intended for reviewers and CI consumers who need to
5+
understand why a local policy rule produced a block, warning, or suppression.
6+
7+
The fields described here are explainability metadata for local policy
8+
decisions. They are not dependency safety verdicts, CVE results, or proof that a
9+
package is safe or unsafe.
10+
11+
## Where the fields appear
12+
13+
Policy decision explanation fields appear only on policy finding objects, such
14+
as:
15+
16+
- `policy_evaluation.blocking_violations`
17+
- `policy_evaluation.warning_violations`
18+
- `policy_evaluation.suppressed_violations`
19+
- `blocking_findings`
20+
- `warning_findings`
21+
- `suppressed_findings`
22+
- provenance policy impact sections
23+
24+
Risk findings in `risks` remain the analyzer's local heuristic findings. They
25+
do not receive policy-decision metadata unless policy evaluation maps them into
26+
policy findings.
27+
28+
## Field contract
29+
30+
- `decision_reason`: Stable reason code for the policy decision.
31+
- `policy_rule`: Policy rule id that produced the decision.
32+
- `severity_source`: Source of the active severity, such as `block_on`,
33+
`warn_on`, `default_block`, or `default_warn`; `null` when there is no active
34+
severity.
35+
- `matched_threshold`: Configured threshold or allowlist value involved in the
36+
decision, when applicable.
37+
- `observed_value`: Observed local value that was compared to the policy rule,
38+
when applicable.
39+
40+
The full JSON report shape is documented in [report-schema.md](report-schema.md).
41+
Policy configuration fields and supported rules are documented in
42+
[policy-schema.md](policy-schema.md).
43+
44+
## Example interpretations
45+
46+
A policy finding with:
47+
48+
```json
49+
{
50+
"decision_reason": "added_package_count_exceeded_threshold",
51+
"policy_rule": "max_added_packages",
52+
"severity_source": "block_on",
53+
"matched_threshold": 0,
54+
"observed_value": 1
55+
}
56+
```
57+
58+
means the local policy compared an observed added-package count of `1` against a
59+
configured threshold of `0`, and the matching rule was active through
60+
`block_on`.
61+
62+
A policy finding with:
63+
64+
```json
65+
{
66+
"decision_reason": "risk_finding_matched_policy_rule",
67+
"policy_rule": "new_package",
68+
"severity_source": "warn_on",
69+
"matched_threshold": null,
70+
"observed_value": "new_package"
71+
}
72+
```
73+
74+
means a local heuristic risk finding matched the `new_package` policy rule, and
75+
the matching rule was active through `warn_on`.
76+
77+
## CI and review usage
78+
79+
Consumers can use these fields to group policy findings by rule, explain why a
80+
local gate failed, or build small job summaries. For example, a CI step can read
81+
`blocking_findings`, print each `policy_rule` and `decision_reason`, and fail
82+
only because the tool already returned a policy failure exit code.
83+
84+
Use `summary.policy` for compact counts and status. Use policy finding
85+
explanation fields when a reviewer needs to inspect why the status was
86+
`warn` or `fail`.
87+
88+
## Compatibility notes
89+
90+
- The fields are additive JSON metadata for policy findings.
91+
- `summary.policy` is unchanged and remains the compact count/status surface.
92+
- Absence of policy findings means policy evaluation did not produce findings
93+
for that section.
94+
- Absence of policy explanation fields outside policy finding objects is
95+
expected.
96+
- Consumers should treat unrecognized future fields as additive report data.
97+
98+
## Non-claims
99+
100+
- The fields do not resolve CVEs.
101+
- The fields do not claim a package is safe or unsafe.
102+
- The fields do not add network behavior.
103+
- The fields do not replace human review of local policy choices.

tools/sbom-diff-and-risk/docs/policy-schema.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ Version `3` supports every version `1` and `2` rule id plus:
106106
- Scorecard evidence remains an auxiliary trust signal. A high score is not
107107
proof of safety, and missing Scorecard data is not proof of risk.
108108

109+
For the JSON policy finding explanation fields emitted after policy evaluation,
110+
see
111+
[policy-decision-explainability.md](policy-decision-explainability.md).
112+
109113
## Version 1 example
110114

111115
```yaml

tools/sbom-diff-and-risk/docs/pypi-production-publishing-decision.md

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ This page records the PR 5 production PyPI gate for `sbom-diff-and-risk`.
44

55
## PR 5 decision
66

7-
Production PyPI publishing is **deferred, but conditionally allowed after the prerequisites below are complete**. In short: production PyPI is currently deferred.
8-
9-
PR 5 does not add an enabled production publishing workflow and does not publish to production PyPI. The successful TestPyPI Trusted Publishing dry-run proves that the package metadata can render on TestPyPI and that the TestPyPI OIDC path can work, but it is not automatic proof that production PyPI publishing is ready.
7+
Production PyPI publishing is **deferred, but conditionally allowed after the
8+
prerequisites below are complete**. In short: production PyPI is currently
9+
deferred.
10+
11+
PR 5 does not add an enabled production publishing workflow and does not publish
12+
to production PyPI. The successful TestPyPI Trusted Publishing dry-run proves
13+
that the package metadata can render on TestPyPI and that the TestPyPI OIDC path
14+
can work, but it is not automatic proof that production PyPI publishing is
15+
ready.
1016

1117
The production gate is intentionally conservative because:
1218

1319
- the production PyPI project does not currently exist under the intended name
14-
- the package metadata has moved to `0.5.0` for the GitHub Release, but production PyPI publishing has not been enabled
20+
- the package metadata has moved beyond the TestPyPI dry-run version, but
21+
production PyPI publishing has not been enabled
1522
- the first production upload should be a deliberate release version, not an old dry-run version
1623
- the production PyPI pending publisher or trusted publisher has not been configured
1724
- the production GitHub environment has not yet been confirmed
@@ -26,18 +33,26 @@ As checked on April 26, 2026:
2633
- `https://test.pypi.org/pypi/sbom-diff-and-risk/json` returned `200`
2734
- TestPyPI reports `sbom-diff-and-risk` version `0.4.1`
2835

29-
This means the intended production project name is not currently visible on production PyPI, while the TestPyPI dry-run project exists. Treat the production name as available for this decision, but re-check immediately before configuration because PyPI can reserve, prohibit, or receive new projects at any time. The first production upload should use a production PyPI pending publisher unless the project is created by a maintainer before the publishing workflow is enabled.
36+
This means the intended production project name is not currently visible on
37+
production PyPI, while the TestPyPI dry-run project exists. Treat the production
38+
name as available for this decision, but re-check immediately before
39+
configuration because PyPI can reserve, prohibit, or receive new projects at any
40+
time. The first production upload should use a production PyPI pending publisher
41+
unless the project is created by a maintainer before the publishing workflow is
42+
enabled.
3043

3144
## First production version
3245

3346
Do not publish `0.4.1` to production PyPI casually.
3447

35-
The first production PyPI version should be `0.5.0` only if v0.5 is approved as the first production package release. Otherwise, defer to a later GitHub release tag.
48+
The first production PyPI version should be an explicitly approved current or
49+
future GitHub release tag. Do not backfill an older release casually.
3650

3751
For the first production upload:
3852

3953
- the GitHub tag should be `v<version>`
40-
- `tools/sbom-diff-and-risk/pyproject.toml` should declare the matching `<version>`
54+
- `tools/sbom-diff-and-risk/pyproject.toml` should declare the matching
55+
`<version>`
4156
- the GitHub release and release assets should be available for the same tag
4257
- the production PyPI workflow should run from the matching tag ref
4358
- the production PyPI upload should use the checked distributions from that workflow run
@@ -55,23 +70,33 @@ Configure the production PyPI publisher to match this identity exactly:
5570
| Trusted Publisher workflow name field | `sbom-diff-and-risk-pypi.yml` |
5671
| GitHub environment | `pypi` |
5772

58-
If production PyPI still has no project for this name, configure a pending publisher for a new project. If the project exists by the time production publishing is implemented, add the trusted publisher to the existing project instead.
59-
60-
Do not create or document a PyPI API token for this workflow. Production upload should use Trusted Publishing / OIDC only.
73+
If production PyPI still has no project for this name, configure a pending
74+
publisher for a new project. If the project exists by the time production
75+
publishing is implemented, add the trusted publisher to the existing project
76+
instead.
77+
78+
Do not create or document a PyPI API token for this workflow. Production upload
79+
should use Trusted Publishing / OIDC only.
6180

6281
PyPI-side setup should use these paths:
6382

64-
- for a new production project, create a pending publisher on production PyPI for project `sbom-diff-and-risk` with the owner, repository, workflow, and environment values above
65-
- for an existing production project, open that project on production PyPI and add a trusted publisher with the same owner, repository, workflow, and environment values
66-
- leave the environment field as `pypi`; if the PyPI publisher omits the environment, it will not match the future publish job identity
83+
- for a new production project, create a pending publisher on production PyPI
84+
for project `sbom-diff-and-risk` with the owner, repository, workflow, and
85+
environment values above
86+
- for an existing production project, open that project on production PyPI and
87+
add a trusted publisher with the same owner, repository, workflow, and
88+
environment values
89+
- leave the environment field as `pypi`; if the PyPI publisher omits the
90+
environment, it will not match the future publish job identity
6791
- do not add a PyPI API token, PyPI password, or GitHub publishing secret as a fallback
6892

6993
## Prerequisites before enabling production publishing
7094

7195
Before adding `.github/workflows/sbom-diff-and-risk-pypi.yml`, maintainers should complete all of these checks:
7296

7397
- confirm the intended production package name still resolves as expected on production PyPI
74-
- choose the first production version, likely `0.5.0` or a later release tag
98+
- choose the first production version as an explicitly approved current or
99+
future release tag
75100
- update `pyproject.toml` to that version
76101
- create or verify the matching GitHub tag and release assets
77102
- create the GitHub environment named `pypi`
@@ -90,7 +115,7 @@ The future production workflow should:
90115
- require an explicit boolean input such as `publish_to_pypi`
91116
- require a confirmation string such as `publish sbom-diff-and-risk to production PyPI`
92117
- require an expected version input and assert that it matches `pyproject.toml`
93-
- require the run ref to be a version tag such as `refs/tags/v0.5.0`
118+
- require the run ref to be a version tag such as `refs/tags/v<version>`
94119
- build the wheel and source distribution once
95120
- run `python -m twine check dist/*`
96121
- upload the checked distributions as a workflow artifact
@@ -99,11 +124,14 @@ The future production workflow should:
99124
- grant `id-token: write` only to the publish job
100125
- avoid production upload on ordinary push or pull request events
101126

102-
The publish step should use `pypa/gh-action-pypi-publish@release/v1` without a `repository-url` override so it targets production PyPI.
127+
The publish step should use `pypa/gh-action-pypi-publish@release/v1` without a
128+
`repository-url` override so it targets production PyPI.
103129

104130
## Provenance boundaries
105131

106-
Production PyPI Trusted Publishing provenance, GitHub workflow artifact attestations, and GitHub Release asset verification answer related but different questions.
132+
Production PyPI Trusted Publishing provenance, GitHub workflow artifact
133+
attestations, and GitHub Release asset verification answer related but
134+
different questions.
107135

108136
PyPI Trusted Publishing provenance answers:
109137

tools/sbom-diff-and-risk/docs/report-schema.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ Explanation fields appear only on policy finding objects. Risk findings in
7171
policy-decision metadata unless a policy evaluation maps them into policy
7272
findings.
7373

74+
For reviewer-facing examples and interpretation guidance, see
75+
[policy-decision-explainability.md](policy-decision-explainability.md).
76+
7477
## Summary contract
7578

7679
`summary` is the stable, compact entry point for automation that needs counts

tools/sbom-diff-and-risk/docs/reviewer-brief.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
`sbom-diff-and-risk` is a local CLI for comparing two SBOMs or dependency manifests and producing deterministic review artifacts: JSON, Markdown, and SARIF. It is built for conservative supply-chain review, not for vulnerability scanning or package reputation scoring.
66

7-
Current released version: `v0.6.0`.
7+
Current released version: `v0.7.0`.
88

99
## Why this project matters
1010

@@ -28,6 +28,7 @@ Dependency review often needs evidence that is stable enough for code review, CI
2828
| What does the tool do? | `README.md`, examples, tests, and generated sample reports. |
2929
| How can a reviewer reproduce the core evidence? | [reviewer-evidence-pack.md](reviewer-evidence-pack.md) for demo, release, TestPyPI, and SARIF verification paths. |
3030
| What is the stable JSON shape? | [report-schema.md](report-schema.md) documents the machine-readable report structure and `summary` contract. |
31+
| How are policy findings explained? | [policy-decision-explainability.md](policy-decision-explainability.md) documents the policy decision metadata in JSON reports. |
3132
| Are default runs offline? | CLI docs, tests for no-enrichment behavior, and explicit enrichment flags. |
3233
| Can code scanning consume the output? | `docs/github-code-scanning.md` and `examples/sample-sarif.sarif`. |
3334
| Can the tool's own artifacts be verified? | `docs/self-provenance.md` for workflow artifact attestations. |

0 commit comments

Comments
 (0)