Skip to content

Add Release.provenance_status - #20326

Merged
di merged 9 commits into
mainfrom
fix/20303
Aug 10, 2026
Merged

di merged 9 commits into
mainfrom
fix/20303

Conversation

@di

@di di commented Jul 24, 2026

Copy link
Copy Markdown
Member

This PR adds Release.provenance_status to address #20303. When Release.provenance_status is present, templates can reference the following fields and properties:

Active Provenance States

A set of string enum values representing all active attestation conditions for the release. Templates can check for specific states using standard Jinja2 in checks, e.g.:

{% if 'inconsistent-provenance' in release.provenance_status.states %}

The values are:

  • no-provenance: 0 files in the release have attestation bundles.
  • full-provenance: 100% of files in the release have attestation bundles.
  • partial-provenance: Some, but not all, files in the release have attestation bundles.
  • inconsistent-provenance: Files within this single release originate from more than one distinct repository URL or more than one distinct workflow filename.
  • lost-provenance: The current release has 0 files with provenance, but a preceding release published within the last 14 days had attested files.
  • changed-provenance: Both the current release and the preceding comparison release have provenance, but their sets of source repositories or workflows differ.

File Count Ratios

Useful for rendering progress badges or ratio summaries (e.g., "3 of 4 files attested"):

  • Release.provenance_status.files_with_provenance (int): Number of files in the release with attestation bundles.
  • Release.provenance_status.total_files (int): Total number of files in the release.

Source Distribution Maps

Dictionaries mapping source URLs and workflow filenames to file counts, useful for rendering repository links, workflow badges, and detailing 'inconsistent-provenance' warnings:

  • Release.provenance_status..repository_counts (dict[str, int]): Maps source repository URLs (e.g., {'https://github.com/org/repo': 2}) to the number of files attested from each.
  • Release.provenance_status..workflow_counts (dict[str, int]): Maps workflow paths/filenames (e.g., {'publish.yml': 2}) to the number of files attested from each.

Comparison Release Context (for Regression Warnings)

When lost-provenance or changed-provenance is present in Release.provenance_status.states, these fields provide baseline context to render comparative warning cards or diff badges:

  • Release.provenance_status.comparison_release (Release | None): The baseline Release object used for comparison (e.g., to render a link: "Compared to v1.0.0").
  • Release.provenance_status.comparison_files_with_provenance (int | None): File counts from the baseline release
  • Release.provenance_status.comparison_total_files (int | None): File counts from the baseline release
    Source Delta Properties (set[str]):
  • Release.provenance_status.added_repositories (set[str]): Sets of repository URLs added between the comparison baseline and the current release.
  • Release.provenance_status.removed_repositories (set[str]): Sets of repository URLs removed between the comparison baseline and the current release.
  • Release.provenance_status.added_workflows (set[str]): Sets of workflow filenames added or removed between the comparison baseline and the current release.
  • Release.provenance_status.removed_workflows (set[str]): Sets of workflow filenames removed between the comparison baseline and the current release.

Fixes #20303.

@di
di requested a review from a team as a code owner July 24, 2026 16:34
@miketheman miketheman self-assigned this Jul 27, 2026
@miketheman miketheman added the security Security-related issues and pull requests label Jul 28, 2026
di and others added 8 commits August 3, 2026 14:35
Publisher identity now comes from the publisher's own type instead of
guessing at attributes. Google Trusted Publisher files contributed
nothing to either counter, so a Google-published release could never be
marked inconsistent or changed. Sources also carry their kind, so the
same repository path on GitHub and GitLab counts as two sources.

An unparsable payload used to raise and take the whole release with it.
It now counts as unreadable, which also stops it reading as a publisher
change: provenance we cannot parse is unknown, not different.

An absent comparison is distinct from an empty one. Both were falsy
before, so the delta properties reported no change whenever the previous
release yielded no sources.

states derives from the counts, which drops a second copy of the
change-detection rule. provenance_status is cached, per-release counting
is one helper, and the comparison window is a constant.
PEP740AttestationViewer shares the publisher dispatch rather than
keeping its own.

Refs #20303
@di
di enabled auto-merge (squash) August 10, 2026 13:12
@di
di merged commit 1072a76 into main Aug 10, 2026
21 checks passed
@di
di deleted the fix/20303 branch August 10, 2026 13:18
@nlhkabu

nlhkabu commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Hi @di

I'm currently using the provenance status functionality on #20408, and I have a question regarding the added and removed sources/configurations.

Currently, {{ release.provenance_status.removed_sources }} returns an object like PublisherSource(kind='GitHub', identity='seed-org/alpha'). This provides enough context for me to build the full URL for each removed source by hardcoding the publisher URL. (The same applies to added sources.)

However, {{ release.provenance_status.removed_workflows }} currently returns only the filename as a string (e.g., 'release.yml').

How would you recommend building the full URL for workflows here?

  • Is it safe to assume the kind from removed_sources applies to removed_workflows in all cases? (same for added)?
  • Or could we theoretically have a situation where the removed source and workflows are on different platforms (e.g., one is GitHub and one is GitLab)?

I wonder whether we could instead update this to return viewer.source and viewer.workflow_url, similar to how it's handled in PEP740AttestationViewer? That might save me from having to reconstruct the URLs manually.

@nlhkabu

nlhkabu commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Also, separately, do we want to handle changes in publisher.email for Google publisher types?

@nlhkabu nlhkabu mentioned this pull request Aug 25, 2026
14 tasks
@di

di commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Is it safe to assume the kind from removed_sources applies to removed_workflows in all cases? (same for added)?

It's an extreme edge case, but no, I think it could be ambiguous if there were multiple sources removed, we wouldn't know which workflow to attribute to which source.

Or could we theoretically have a situation where the removed source and workflows are on different platforms (e.g., one is GitHub and one is GitLab)?

That could happen, we could also have two removed sources from the same platform (like two different GitHub repos publishing to the same PyPI project -- probably rare, but possible)

I wonder whether we could instead update this to return viewer.source and viewer.workflow_url, similar to how it's handled in PEP740AttestationViewer? That might save me from having to reconstruct the URLs manually.

Yes, I think that would make sense, right now removed_workflows doesn't seem very useful.

Also, separately, do we want to handle changes in publisher.email for Google publisher types?

Yes!

@nlhkabu

nlhkabu commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Thanks @di

FYI, right now I've just output the data like this in #20408

image image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security-related issues and pull requests trusted-publishing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface release provenance states for templates to consume

3 participants