Skip to content

Add cci trusted publisher attestation#1

Open
meeech wants to merge 30 commits into
add-cci-trusted-publisher-take-2from
add-cci-trusted-publisher-attestation
Open

Add cci trusted publisher attestation#1
meeech wants to merge 30 commits into
add-cci-trusted-publisher-take-2from
add-cci-trusted-publisher-attestation

Conversation

@meeech

@meeech meeech commented Feb 4, 2026

Copy link
Copy Markdown
Owner

add attestation for circleci trusted publishing to the warehouse

pipeline_definition_id=PIPELINE_DEF_ID,
)

# No claims - no URL

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this even worth testing out? under what scenario would i publish without claims?

== "https://app.circleci.com/workflow/stored-workflow/job/stored-job"
)

# Missing job_id returns None

@meeech meeech Feb 4, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not clear to me how this would happen? i mean, its fine to assert it, but trying to understand in what scenario (besides bug in cci sending a claim) this happens, since our claims should always include these 2 pieces of information.

Comment thread warehouse/oidc/models/circleci.py Outdated
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch from 5b980b7 to 459fa6e Compare February 5, 2026 04:05
@meeech meeech force-pushed the add-cci-trusted-publisher-attestation branch from 30e7557 to c21a926 Compare February 5, 2026 04:18
Comment thread warehouse/oidc/models/circleci.py
@meeech

meeech commented Feb 5, 2026

Copy link
Copy Markdown
Owner Author

update:
Works locally (huzzah!)

  • ~~Need to beef up the Provenance with some more links. ~~
  • Unsure if thats a pypi-attestations or warehouse implementation detail (or both - will dig in) (looks like it was just warehouse side. I had enough info from pypi-attestations
image

@meeech

meeech commented Feb 5, 2026

Copy link
Copy Markdown
Owner Author

and the whl

image

<li>
Build Job that produced the artifact: <a href="{{ viewer.run_invocation_uri }}"><code>{{ viewer.run_invocation_uri }}</code></a>
</li>
{% if viewer.source %}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: so this is part of the OIDC claim. BUT: this (and ref) is optional when setting up the trusted publisher. So they will usually always exist on the cert, but might not be part of the requirement for publishing via the TP.

I want to lean towards expose most info possible to end user.

But is that the convention?
Or should I be checking if viewer.source and bundle.publisher.vcs_origin both exist before exposing this info? (same for vcs_ref)

@meeech meeech force-pushed the add-cci-trusted-publisher-attestation branch from 295bcab to 74c456e Compare February 7, 2026 00:07
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch from 459fa6e to 669a67a Compare February 7, 2026 15:32
@meeech meeech force-pushed the add-cci-trusted-publisher-attestation branch from 31597a9 to 4b2bc07 Compare February 7, 2026 15:32
meeech and others added 16 commits February 18, 2026 12:11
Add CircleCIPublisher and PendingCircleCIPublisher models following
the existing OIDC publisher pattern. CircleCI identifies projects by
circleci_org_id and circleci_project_id (UUIDs from OIDC claims).

- CircleCIPublisherMixin with shared logic
- CircleCIPublisher for active publishers
- PendingCircleCIPublisher for pending registration
- Export models and issuer URL from __init__.py
- Register in OIDC_PUBLISHER_CLASSES, OIDC_ISSUER_SERVICE_NAMES,
  and OIDC_ISSUER_ADMIN_FLAGS in utils.py

Note: Column names use circleci_ prefix to avoid collision with
PendingOIDCPublisher.organization_id (PyPI org FK).

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
- Add DISALLOW_CIRCLECI_OIDC admin flag for killswitch control
- Register CircleCI OIDC publisher service factory

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
- CircleCIPublisherBase with circleci_org_id and circleci_project_id fields
- CircleCIPublisherForm for project-level publisher management
- PendingCircleCIPublisherForm for pending publisher registration
- Export forms from __init__.py

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Add add_circleci_oidc_publisher view to ManageOIDCPublisherViews
for registering CircleCI trusted publishers on projects.

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Add CircleCI support to pending publisher management in account views
for registering publishers before project creation.

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Add CircleCI support to organization-level pending publisher management.

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Add CircleCI publisher form and display sections to:
- Project publishing template
- Account publishing template
- Organization publishing template
- Base manage template (nav update if any)

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Create circleci_oidc_publishers and pending_circleci_oidc_publishers
tables with circleci_org_id and circleci_project_id columns.

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
- CircleCIPublisherFactory and PendingCircleCIPublisherFactory
- Model tests for CircleCIPublisher and PendingCircleCIPublisher
- Form validation tests for CircleCI publisher forms
- View tests for project, account, and organization publishers

Amp-Thread-ID: https://ampcode.com/threads/T-019bb846-115f-75e8-9c39-9694e10df5da
Co-authored-by: Amp <amp@ampcode.com>
Add wtforms.validators.UUID to all CircleCI OIDC publisher form fields:
- circleci_org_id (required)
- circleci_project_id (required)
- pipeline_definition_id (required)
- context_id (optional)

This ensures users submit valid UUIDs matching CircleCI's identifier format.

Also update tests to:
- Include pipeline_definition_id in test data (now required)
- Add test for optional context_id with valid UUID
- Add test for missing pipeline_definition_id
- Add parametrized test for invalid UUID on required fields
- Add test for invalid context_id UUID
Add support for two optional VCS claims in CircleCI OIDC publishers:
- vcs_ref: git ref like 'refs/heads/main'
- vcs_origin: VCS origin like 'github.com/organization-123/repo-1'

These claims allow users to constrain publishers to specific branches
or repositories for additional security.

Changes:
- Add model columns vcs_ref and vcs_origin (nullable)
- Move claims from __unchecked_claims__ to __optional_verifiable_claims__
- Add _check_optional_string helper for simple string matching
- Update __getattr__ to map claim names to attributes
- Update exists(), admin_details, unique constraints, and reify()
- Add form fields for vcs_ref and vcs_origin
- Update all views that create CircleCI publishers
Update the CircleCI OIDC publisher migration to include:
- vcs_ref column (nullable)
- vcs_origin column (nullable)
- Updated unique constraints to include both fields
Update test data in test_oidc_publishers.py to use valid UUID format
for CircleCI fields (circleci_org_id, circleci_project_id,
pipeline_definition_id) and include all required form fields
(context_id, vcs_ref, vcs_origin).

This ensures test data matches the UUID validation requirements
added to the CircleCI form fields.
Add pipeline_definition_id, context_id, vcs_ref, and vcs_origin to
the mocked CircleCI form in test_organizations.py to match the
complete form field requirements.
Add tests for the optional vcs_ref and vcs_origin fields:
- test_validate_with_optional_vcs_ref
- test_validate_with_optional_vcs_origin
- test_validate_with_all_optional_fields
Add comprehensive tests for the new optional VCS claims:

- TestCheckOptionalString: Tests for the _check_optional_string helper
  - Empty ground truth always passes
  - Required value fails without claim
  - Required value matches/doesn't match claim

- TestCircleCIPublisher updates:
  - test_admin_details_with_vcs_ref
  - test_admin_details_with_vcs_origin
  - test_admin_details_with_all_optional_fields
  - Updated test_getattr_maps_claims_to_attributes

- TestPendingCircleCIPublisher updates:
  - Updated test_reify_creates_publisher with vcs fields
  - Updated test_reify_returns_existing_publisher with vcs fields

Also update new_signed_claims helper to accept vcs_ref and vcs_origin.
meeech and others added 10 commits February 18, 2026 12:11
Add the optional VCS fields to all three CircleCI publisher templates:
- manage/project/publishing.html
- manage/account/publishing.html
- manage/organization/publishing.html

Each field includes:
- Label with (optional) indicator
- Placeholder text showing expected format
- Help text explaining the field's purpose

Amp-Thread-ID: https://ampcode.com/threads/T-019be17b-aad4-7691-8ab4-01828eebb650
Co-authored-by: Amp <amp@ampcode.com>
Regenerate migration with correct down_revision (31ac9b5e1e8b) to chain
after upstream 'Add ADMINISTRATIVE to BanReason enum' migration.

Amp-Thread-ID: https://ampcode.com/threads/T-019bfd26-1169-72d6-81c6-b682c6daea4d
Co-authored-by: Amp <amp@ampcode.com>
Add the attestation_identity property to CircleCIPublisherMixin, following
the pattern established by GitHub, GitLab, and Google publishers.

Currently returns None as pypi-attestations library does not yet have a
CircleCIPublisher identity class. Fulcio already supports CircleCI OIDC
tokens, so this prepares the infrastructure for when upstream support
is added.

Refs: sigstore/fulcio#591
Amp-Thread-ID: https://ampcode.com/threads/T-019bfff2-9b8a-7199-ab46-631fcb14f9d3
Co-authored-by: Amp <amp@ampcode.com>
Add tests for parity with GitHub/GitLab model tests:
- all_known_claims() assertion for claim set stability
- Missing required claims raise KeyError
- DB uniqueness constraint (UniqueViolation) test
- verify_url() returns False for CircleCI
- Multi-constraint lookup tests (vcs_ref, vcs_origin)
- Exact InvalidPublisherError message test
- Parametrized optional claim verification tests

Signed-off-by: meeech <4623+meeech@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c003a-2977-70f9-ad05-cce7fb3236a0
Co-authored-by: Amp <amp@ampcode.com>
Add tests for parity with GitHub/GitLab form tests:
- ProjectNameUnavailable*Error variants (Invalid, Existing, Stdlib, Prohibited, Similar)
- Optional field consistency tests for vcs_ref, vcs_origin, context_id
- Parametrized invalid field tests for required UUID fields
- Empty string vs None consistency for optional fields

Signed-off-by: meeech <4623+meeech@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c003a-2977-70f9-ad05-cce7fb3236a0
Co-authored-by: Amp <amp@ampcode.com>
Fill in actual values for optional CircleCI fields (context_id, vcs_ref,
vcs_origin) to match the pattern used by GitHub/GitLab tests which
populate their optional fields with real values.

Signed-off-by: meeech <4623+meeech@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c003a-2977-70f9-ad05-cce7fb3236a0
Co-authored-by: Amp <amp@ampcode.com>
Add pipeline_definition_id, context_id, vcs_ref, and vcs_origin to the
CircleCI trusted publisher display in manage_base.html. Also update test
factories to include vcs_ref and vcs_origin fields.

Amp-Thread-ID: https://ampcode.com/threads/T-019c2939-421d-757c-9608-2f7b1758b9c0
Co-authored-by: Amp <amp@ampcode.com>
ran make resetdb and make initdb, seems fine
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch from 1e6acfb to bdae7b2 Compare February 18, 2026 17:11
meeech and others added 4 commits February 18, 2026 12:12
Replaces the placeholder None return with a CircleCIPublisher identity
using project_id, pipeline_definition_id, and optional vcs_origin/vcs_ref.

Amp-Thread-ID: https://ampcode.com/threads/T-019c2459-0627-751e-b732-965e5924ad58
Co-authored-by: Amp <amp@ampcode.com>
stored_claims returns job_id and workflow_id from OIDC token claims.
publisher_url uses these to construct a clickable CircleCI job URL:
https://app.circleci.com/workflow/{workflow_id}/job/{job_id}

Amp-Thread-ID: https://ampcode.com/threads/T-019c2459-0627-751e-b732-965e5924ad58
Co-authored-by: Amp <amp@ampcode.com>
@meeech meeech force-pushed the add-cci-trusted-publisher-attestation branch from 4b2bc07 to 1894565 Compare February 18, 2026 17:12
@meeech meeech marked this pull request as ready for review February 21, 2026 16:37
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch from bdae7b2 to 92ccbca Compare February 23, 2026 00:31
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch 3 times, most recently from 6bb3769 to f54ede0 Compare March 7, 2026 05:21
@meeech meeech force-pushed the add-cci-trusted-publisher-take-2 branch from f54ede0 to de7dcf9 Compare March 12, 2026 03:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant