Add circleci to pypi attestations#166
Conversation
| f"Verification failed: provenance was signed by service account " | ||
| f'"{publisher.email}", expected "{args.gcp_service_account}"' | ||
| ) | ||
| elif isinstance(publisher, CircleCIPublisher): |
There was a problem hiding this comment.
tbh - not entirely clear how to test this properly. (help wanted)
In examining the payload from other packages, I can see the publisher comes as part of the call https://pypi.org/integrity/package/version/filename/provenance but not clear what I should be validating against? Would it be enough to just use one of the claims? eg: the project id?
note to self: this value thats being checked maps to the values of attestation_identity. eg: https://github.com/pypi/warehouse/blob/5b980b74b3eee5e79580dc4672abad3d93f14472/warehouse/oidc/models/github.py#L306
I guess what I am wondering about is whats needed here to verify? Like is just the project_id enough? or would i want to use the pipeline_id as well? Unless I misunderstand, after this stage there should be further certificate validation happening of the fulcio cert?
Any guidance here is welcome :D
There was a problem hiding this comment.
You can see what I did for warehouse here - meeech/warehouse#1
This is a pr stacked off my pr for adding circleci as a trusted publisher (it wouldnt let me open a pr on the parent against a pr)
|
Thanks @meeech! I'll try and give this a review in the next day or so. |
|
update:
@woodruffw
|
|
@woodruffw update: i beefed up the provenance display in warehouse. in the end, didnt have to touch this pr any further, so it's ready for review whenever you are |
- Add _CircleCITrustedPublisherPolicy to verify certificates against CircleCI OIDC issuer - Verify organization_id via OIDC issuer (https://oidc.circleci.com/org/<org_id>) - Verify project_id via Build Signer URI extension - Add optional repository field to verify source repository URI (oidc.circleci.com/vcs-origin) - Update CLI to handle CircleCIPublisher verification - Export CircleCIPublisher from package __init__.py - Add tests for discriminator and wrong kind validation Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
…ields Required fields: - organization_id: verified via OIDC issuer - project_id: verified via Build Signer URI - pipeline_definition_id: verified via Build Signer URI (exact match) Optional fields: - context_id: CircleCI context ID from oidc.circleci.com/context-ids - vcs_origin: source repository from oidc.circleci.com/vcs-origin - vcs_ref: git ref from oidc.circleci.com/vcs-ref These fields align with PyPI's trusted publisher requirements for CircleCI. Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
context_id cannot be verified via attestation since Fulcio does not map oidc.circleci.com/context-ids to a certificate extension. This field belongs in warehouse's OIDCPublisher model for trusted publishing verification, not in pypi-attestations for attestation verification. Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
CircleCI is updating their OIDC issuer to no longer include the organization ID in the path. Since org-id is not mapped to a Fulcio certificate extension, it cannot be verified via attestation and is removed from CircleCIPublisher. Required fields now: - project_id - pipeline_definition_id Optional fields: - vcs_origin - vcs_ref Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
When oidc.circleci.com/ssh-rerun is true, the runner_environment cert extension is set to 'ssh-rerun'. These jobs are not trusted for publishing as they indicate manual SSH access to the CI environment. This provides defense-in-depth alongside PyPI's trusted publishing check, ensuring attestations from SSH rerun jobs are rejected during both upload and downstream verification. Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
Add --circleci-project-id and --circleci-pipeline-definition-id flags to verify provenance from CircleCI publishers. The CLI now validates that the provenance publisher's project_id and pipeline_definition_id match the expected values provided via flags. Amp-Thread-ID: https://ampcode.com/threads/T-019c0ccd-f336-72fb-ae44-77b840fb92aa Co-authored-by: Amp <amp@ampcode.com>
leave that as a concern of pypi warehouse to reject any tp with this value (and remove a useless comment)
164f43c to
236682c
Compare
|
sorry just noticed the fail on the lint and tests. will fix that, also will enable the actions in my repo |
Add tests for _CircleCITrustedPublisherPolicy and CircleCIPublisher in test_impl.py covering policy verification, optional vcs claims, and failure paths for wrong build signer URI and issuer. Add CLI tests in test_cli.py for the verify pypi CircleCI branch covering missing project ID, missing pipeline definition ID, wrong project ID, wrong pipeline definition ID, and the happy path. Include real CircleCI-signed test assets: wheel, attestation, provenance, and extracted certificate PEM. Amp-Thread-ID: https://ampcode.com/threads/T-019c6230-33ea-767c-aa18-424c9eebb577 Co-authored-by: Amp <amp@ampcode.com>
|
Ok, so the test cov issue should be resolved now. Sorry about the confusion. I got tripped up on the online tests. Tested with a fork local pr, and now looked good. |
|
@di @woodruffw I think this is ready for review? Or would you rather wait till first pr for warehouse is done? |
di
left a comment
There was a problem hiding this comment.
Seems fine to me, will let @woodruffw review as well.


Summary
In an effort to add CircleCI as a Trusted Publisher for pypi/warehouse, we need to add a CCI Publisher for attestations.
note: to test properly in a live env requires1.6.1 is released so we good here. Do we need to bump up the required id package? Since the latest one will be required to work with cci once this is merged?id>=1.6.0. 1.6.0 was yanked (unrelated reason), but can still be installed if testing this before 1.6.1 is released.Help needed
I'm uncertain about some of the choices I've made here.
I will comment inline where these open questions I have are.
In general I would refer back to gh/gl patterns to help guide this work.
I would need someone who knows this specific project/domain a bit better to give some guidance.
Open to a regular PR review.
But I am also open to a sync review (on the pypa discord?) to walk through this together to speed things up (and allow quick follow up questions where its not clear to me).
related pr:
pypi/warehouse#19349 - warehouse - add circleci as a trusted publisher
meeech/warehouse#1 (stacked off of ☝🏼 )
di/id#438 - updated the oidc issuer when getting ambient id
Checklist
(sorry if I should not be bumping the version? lmk I'll remove it)
Making a release
src/pypi_attestations/__init__.py