Skip to content

ci(release): publish from the protected release environment with project-scoped tokens - #558

Open
mlieberman85 wants to merge 1 commit into
darnitdevorg:mainfrom
mlieberman85:release-environment-gate
Open

mlieberman85 wants to merge 1 commit into
darnitdevorg:mainfrom
mlieberman85:release-environment-gate

Conversation

@mlieberman85

Copy link
Copy Markdown
Contributor

Summary

The PyPI credential is currently PYPI_API_TOKEN, an account-scoped repository secret. Any workflow run in the repository can read it, so anyone with write access could read or use it from a branch. This PR gates publishing:

  • Each publish-* job in release.yml runs in environment: release.
  • Each job reads its own project-scoped token from that environment: PYPI_TOKEN_DARNIT_CORE, PYPI_TOKEN_DARNIT_BASELINE, PYPI_TOKEN_DARNIT_GITTUF, PYPI_TOKEN_DARNIT_REPRODUCIBILITY, PYPI_TOKEN_DARNIT_MCP.
  • packaging/README.md documents the setup.

The release environment is already configured:

  • Required reviewers: mlieberman85, Marc-cn.
  • Deployment policy: v* tags and the main branch (main is for the workflow_dispatch re-release path).

Before the next release (maintainer steps)

  1. Create a project-scoped PyPI token for each of the five packages and add each one as a release environment secret. The commands are in packaging/README.md.
  2. Delete the repository secret: gh secret delete PYPI_API_TOKEN --repo darnitdevorg/darnit.
  3. Revoke the old account-scoped token on PyPI.

Until step 1 is done, a release's publish jobs fail with a 403 and nothing is published.

Type of Change

  • Bug fix (non-breaking change fixing an issue)
  • New feature (non-breaking change adding functionality)
  • Breaking change (fix or feature causing existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)

This is a CI and release-process security change; product code is unchanged.

Testing

  • Tests pass locally (uv run pytest tests/ -v): not applicable, no product code changed
  • Added tests for new functionality (if applicable)
  • Linting passes: actionlint .github/workflows/release.yml

AI assistance

  • No AI assistance was used
  • AI assistance was used

Claude (Claude Code, claude-opus-5-5) found the exposure, configured the release environment through the API at my direction, and made this change. This description was also drafted with Claude. The commit carries an Assisted-by: Claude:claude-opus-5-5 trailer.

Additional Notes

  • Publish Python packages with PyPI Trusted Publishing #519 (Trusted Publishing) would remove the tokens entirely. Its jobs already use environment: release.
  • Unrelated finding: the parity tier-2 workflows name environments parity-tier2 and parity-tier2-openai and say they are "gated with required reviewers", but neither environment exists. A dispatched run would create them unprotected, and fail for lack of secrets.

🤖 Generated with Claude Code

…ect-scoped tokens

PYPI_API_TOKEN was an account-scoped repository secret, readable by any
workflow run in the repository. Each publish job now runs in the release
environment (required reviewers, deployments only from v* tags or main)
and reads its own project-scoped token from that environment.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Michael Lieberman <mlieberman85@gmail.com>
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